Skip to content

Commit 087e37e

Browse files
committed
feat: Verify package name in real-time (#1213)
1 parent 077afc2 commit 087e37e

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

extension/package-lock.json

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extension/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@
864864
"@types/fs-extra": "^9.0.13",
865865
"@types/glob": "^7.2.0",
866866
"@types/google-protobuf": "^3.15.5",
867+
"@types/lodash": "^4.14.182",
867868
"@types/mocha": "^9.1.0",
868869
"@types/node": "^14.14.31",
869870
"@types/sinon": "^10.0.11",
@@ -890,6 +891,7 @@
890891
"await-lock": "^2.1.0",
891892
"fs-extra": "^10.0.1",
892893
"get-port": "^5.1.1",
894+
"lodash": "^4.17.21",
893895
"minimatch": "^3.0.5",
894896
"string-argv": "^0.3.1",
895897
"tree-kill": "^1.2.2",

extension/src/createProject/SpecifySourcePackageNameStep.ts

+37-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import * as vscode from "vscode";
55
import { IProjectCreationMetadata, IProjectCreationStep, StepResult } from "./types";
6+
import { asyncDebounce } from "./utils";
67

78
export class SpecifySourcePackageNameStep implements IProjectCreationStep {
89
public static GET_NORMALIZED_PACKAGE_NAME = "getNormalizedPackageName";
@@ -11,12 +12,17 @@ export class SpecifySourcePackageNameStep implements IProjectCreationStep {
1112
if (!metadata.client) {
1213
return StepResult.STOP;
1314
}
15+
const getNormalizedPackageNameTrigger = asyncDebounce(
16+
metadata.client.getNormalizedPackageName,
17+
500 /** ms */,
18+
metadata.client
19+
);
1420
const disposables: vscode.Disposable[] = [];
1521
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1622
const specifySourcePackageNamePromise = new Promise<StepResult>(async (resolve, _reject) => {
1723
const inputBox = vscode.window.createInputBox();
1824
const defaultName = metadata.sourcePackageName || "";
19-
const normalizedName = await metadata.client.getNormalizedPackageName(defaultName);
25+
const normalizedName = await getNormalizedPackageNameTrigger(defaultName);
2026
if (!normalizedName) {
2127
return resolve(StepResult.STOP);
2228
}
@@ -25,7 +31,7 @@ export class SpecifySourcePackageNameStep implements IProjectCreationStep {
2531
})`;
2632
inputBox.prompt = "Input source package name of your project.";
2733
inputBox.placeholder = "e.g. " + normalizedName;
28-
inputBox.value = normalizedName;
34+
inputBox.value = normalizedName as string;
2935
inputBox.ignoreFocusOut = true;
3036
inputBox.enabled = true;
3137
if (metadata.steps.length) {
@@ -39,15 +45,26 @@ export class SpecifySourcePackageNameStep implements IProjectCreationStep {
3945
);
4046
}
4147
disposables.push(
48+
inputBox.onDidChangeValue(async () => {
49+
const normalizedName = await getNormalizedPackageNameTrigger(inputBox.value);
50+
if (!normalizedName) {
51+
return;
52+
} else if (normalizedName !== inputBox.value) {
53+
this.setInputInvalid(inputBox, normalizedName as string);
54+
} else {
55+
this.setInputValid(inputBox);
56+
}
57+
}),
4258
inputBox.onDidAccept(async () => {
4359
const normalizedName = await metadata.client.getNormalizedPackageName(inputBox.value);
44-
if (normalizedName === inputBox.value) {
60+
if (!normalizedName) {
61+
return;
62+
} else if (normalizedName !== inputBox.value) {
63+
this.setInputInvalid(inputBox, normalizedName as string);
64+
} else {
4565
metadata.sourcePackageName = inputBox.value;
4666
metadata.nextStep = undefined;
4767
resolve(StepResult.NEXT);
48-
} else {
49-
inputBox.enabled = false;
50-
inputBox.validationMessage = `Invalid source package name, suggest name: ${normalizedName}`;
5168
}
5269
}),
5370
inputBox.onDidHide(() => {
@@ -64,6 +81,20 @@ export class SpecifySourcePackageNameStep implements IProjectCreationStep {
6481
disposables.forEach((d) => d.dispose());
6582
}
6683
}
84+
85+
private setInputInvalid(inputBox: vscode.InputBox, normalizedName: string) {
86+
if (inputBox) {
87+
inputBox.enabled = false;
88+
inputBox.validationMessage = `Invalid source package name, suggest name: ${normalizedName}`;
89+
}
90+
}
91+
92+
private setInputValid(inputBox: vscode.InputBox) {
93+
if (inputBox) {
94+
inputBox.enabled = true;
95+
inputBox.validationMessage = undefined;
96+
}
97+
}
6798
}
6899

69100
export const specifySourcePackageNameStep = new SpecifySourcePackageNameStep();

extension/src/createProject/utils.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
/* eslint-disable @typescript-eslint/no-explicit-any */
5+
import { debounce } from "lodash";
6+
7+
export function asyncDebounce(func: any, wait: any, bind: any) {
8+
const debounced = debounce(async (resolve, reject, bindSelf, args) => {
9+
try {
10+
const result = await func.bind(bindSelf)(...args);
11+
resolve(result);
12+
} catch (error) {
13+
reject(error);
14+
}
15+
}, wait);
16+
17+
function returnFunc(...args: any[]) {
18+
return new Promise((resolve, reject) => {
19+
debounced(resolve, reject, bind, args);
20+
});
21+
}
22+
23+
return returnFunc;
24+
}

0 commit comments

Comments
 (0)