@azure/api-management-custom-widgets-scaffolder 1.0.0-beta.1 → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,7 +12,7 @@ the [official Azure documentation](https://aka.ms/apimdocs/portal/customwidgets)
12
12
 
13
13
  ### Currently supported environments
14
14
 
15
- - [LTS versions of Node.js](https://nodejs.org/about/releases/)
15
+ - [LTS versions of Node.js](https://github.com/nodejs/release#release-schedule)
16
16
  - Latest versions of Safari, Chrome, Edge, and Firefox
17
17
 
18
18
  ### Prerequisites
package/bin/execute.js CHANGED
@@ -17,7 +17,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
17
17
  var inquirer__default = /*#__PURE__*/_interopDefaultLegacy(inquirer);
18
18
  var Parser__default = /*#__PURE__*/_interopDefaultLegacy(Parser);
19
19
  var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
20
- var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
21
20
  var mustache__default = /*#__PURE__*/_interopDefaultLegacy(mustache);
22
21
 
23
22
  // Copyright (c) Microsoft Corporation.
@@ -54,10 +53,12 @@ const fieldIdToName = {
54
53
  displayName: "Widget display name",
55
54
  technology: "Technology",
56
55
  iconUrl: "iconUrl",
57
- resourceId: "Azure API Management resource ID",
56
+ resourceId: "Azure API Management resource ID (following format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<api-management service-name>)",
58
57
  managementApiEndpoint: "Management API hostname",
59
58
  apiVersion: "Management API version",
60
59
  openUrl: "Developer portal URL",
60
+ configAdvancedTenantId: "Tenant ID",
61
+ configAdvancedRedirectUri: "Redirect URI",
61
62
  };
62
63
  const prefixUrlProtocol = (value) => /https?:\/\//.test(value) ? value : `https://${value}`;
63
64
  const validateRequired = (name, msg = `The “${name}” parameter is required.`) => (input) => (input != null && input !== "") || msg;
@@ -95,12 +96,7 @@ const validateDeployConfig = {
95
96
  ? true
96
97
  : "Resource ID needs to be a valid Azure resource ID. For example, subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/contoso-group/providers/Microsoft.ApiManagement/service/contoso-apis.";
97
98
  },
98
- managementApiEndpoint: (input) => {
99
- const required = validateRequired(fieldIdToName.managementApiEndpoint)(input);
100
- if (required !== true)
101
- return required;
102
- return validateUrl(fieldIdToName.managementApiEndpoint)(input);
103
- },
99
+ managementApiEndpoint: (input) => validateRequired(fieldIdToName.managementApiEndpoint)(input),
104
100
  };
105
101
  const validateMiscConfig = {
106
102
  openUrl: (input) => {
@@ -108,6 +104,14 @@ const validateMiscConfig = {
108
104
  return true;
109
105
  return validateUrl(fieldIdToName.openUrl)(input);
110
106
  },
107
+ configAdvancedTenantId: () => {
108
+ return true;
109
+ },
110
+ configAdvancedRedirectUri: (input) => {
111
+ if (!input)
112
+ return true;
113
+ return validateUrl(fieldIdToName.openUrl)(input);
114
+ },
111
115
  };
112
116
  const promptWidgetConfig = (partial) => inquirer__default["default"].prompt([
113
117
  {
@@ -127,7 +131,7 @@ const promptWidgetConfig = (partial) => inquirer__default["default"].prompt([
127
131
  ],
128
132
  },
129
133
  ], partial);
130
- const promptDeployConfig = (partial) => inquirer__default["default"].prompt([
134
+ const promptServiceInformation = (partial) => inquirer__default["default"].prompt([
131
135
  {
132
136
  name: "resourceId",
133
137
  type: "input",
@@ -136,9 +140,16 @@ const promptDeployConfig = (partial) => inquirer__default["default"].prompt([
136
140
  },
137
141
  {
138
142
  name: "managementApiEndpoint",
139
- type: "input",
143
+ type: "list",
140
144
  message: fieldIdToName.managementApiEndpoint,
141
- default: "management.azure.com",
145
+ choices: [
146
+ {
147
+ name: "management.azure.com (if you're not sure what to select, use this option)",
148
+ value: "management.azure.com",
149
+ },
150
+ { name: "management.usgovcloudapi.net", value: "management.usgovcloudapi.net" },
151
+ { name: "management.chinacloudapi.cn", value: "management.chinacloudapi.cn" },
152
+ ],
142
153
  transformer: prefixUrlProtocol,
143
154
  validate: validateDeployConfig.managementApiEndpoint,
144
155
  },
@@ -157,6 +168,20 @@ const promptMiscConfig = (partial) => inquirer__default["default"].prompt([
157
168
  transformer: prefixUrlProtocol,
158
169
  validate: validateMiscConfig.openUrl,
159
170
  },
171
+ {
172
+ name: "configAdvancedTenantId",
173
+ type: "input",
174
+ message: fieldIdToName.configAdvancedTenantId +
175
+ " to be used in Azure Identity InteractiveBrowserCredential class (optional)",
176
+ validate: validateMiscConfig.openUrl,
177
+ },
178
+ {
179
+ name: "configAdvancedRedirectUri",
180
+ type: "input",
181
+ message: fieldIdToName.configAdvancedRedirectUri +
182
+ " to be used in Azure Identity InteractiveBrowserCredential class (optional; default is http://localhost:1337)",
183
+ validate: validateMiscConfig.openUrl,
184
+ },
160
185
  ], partial);
161
186
 
162
187
  class YError extends Error {
@@ -833,14 +858,11 @@ async function getTemplates(template) {
833
858
  return [...sharedFiles, ...templateFiles];
834
859
  }
835
860
  async function getFiles(path) {
836
- return new Promise((resolve, reject) => {
837
- glob__default["default"](path, { dot: true }, (error, matches) => {
838
- if (error) {
839
- reject(error);
840
- }
841
- resolve(matches);
842
- });
843
- });
861
+ // Starting from glob v8 `\` is only used as an escape character, and never as a path separator in glob patterns.
862
+ // Glob pattern paths must use forward-slashes as path separators.
863
+ // See https://github.com/isaacs/node-glob/blob/af57da21c7722bb6edb687ccd4ad3b99d3e7a333/changelog.md#80
864
+ const normalizedPath = path.replace(/\\/g, "/");
865
+ return glob.glob(normalizedPath, { dot: true });
844
866
  }
845
867
 
846
868
  // Copyright (c) Microsoft Corporation.
@@ -853,7 +875,7 @@ const templateSuffix = ".mustache";
853
875
  * @param options - JSON object with other data, which will not be stored in the DevPortal.
854
876
  */
855
877
  async function generateProject(widgetConfig, deploymentConfig, options = {}) {
856
- const { openUrl } = options;
878
+ const { openUrl, configAdvancedTenantId, configAdvancedRedirectUri } = options;
857
879
  const openUrlParsed = openUrl ? new URL(openUrl) : null;
858
880
  if (openUrlParsed) {
859
881
  openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));
@@ -863,6 +885,15 @@ async function generateProject(widgetConfig, deploymentConfig, options = {}) {
863
885
  port: OVERRIDE_DEFAULT_PORT,
864
886
  open: openUrlParsed ? openUrlParsed.toString() : true,
865
887
  };
888
+ const configAdditional = {
889
+ interactiveBrowserCredentialOptions: { redirectUri: "http://localhost:1337" },
890
+ };
891
+ if (configAdvancedTenantId) {
892
+ configAdditional.interactiveBrowserCredentialOptions.tenantId = configAdvancedTenantId;
893
+ }
894
+ if (configAdvancedRedirectUri) {
895
+ configAdditional.interactiveBrowserCredentialOptions.redirectUri = configAdvancedRedirectUri;
896
+ }
866
897
  const renderTemplate = async (file) => {
867
898
  const isTemplate = file.endsWith(templateSuffix);
868
899
  const encoding = file.endsWith(".ttf") ? "binary" : "utf8";
@@ -873,6 +904,7 @@ async function generateProject(widgetConfig, deploymentConfig, options = {}) {
873
904
  displayName: widgetConfig.displayName,
874
905
  config: JSON.stringify(Object.assign(Object.assign({}, widgetConfig), { name }), null, "\t"),
875
906
  configDeploy: JSON.stringify(deploymentConfig, null, "\t"),
907
+ configAdditional: JSON.stringify(configAdditional, null, "\t"),
876
908
  serverSettings: JSON.stringify(serverSettings, null, "\t"),
877
909
  });
878
910
  }
@@ -907,23 +939,23 @@ async function main() {
907
939
  white("Specify the custom widget configuration.");
908
940
  const widgetConfig = await getConfig(promptWidgetConfig, validateWidgetConfig);
909
941
  white("Specify the Azure API Management service configuration.");
910
- const deployConfig = await getConfig(promptDeployConfig, validateDeployConfig);
942
+ const serviceInformation = await getConfig(promptServiceInformation, validateDeployConfig);
911
943
  white("Specify other options");
912
944
  const miscConfig = await getConfig(promptMiscConfig, validateMiscConfig);
913
- if (deployConfig.resourceId[0] === "/") {
914
- deployConfig.resourceId = deployConfig.resourceId.slice(1);
945
+ if (serviceInformation.resourceId[0] === "/") {
946
+ serviceInformation.resourceId = serviceInformation.resourceId.slice(1);
915
947
  }
916
- if (deployConfig.resourceId.slice(-1) === "/") {
917
- deployConfig.resourceId = deployConfig.resourceId.slice(0, -1);
948
+ if (serviceInformation.resourceId.slice(-1) === "/") {
949
+ serviceInformation.resourceId = serviceInformation.resourceId.slice(0, -1);
918
950
  }
919
- if (deployConfig.apiVersion === "") {
920
- delete deployConfig.apiVersion;
951
+ if (serviceInformation.apiVersion === "") {
952
+ delete serviceInformation.apiVersion;
921
953
  }
922
- deployConfig.managementApiEndpoint = prefixUrlProtocol(deployConfig.managementApiEndpoint);
954
+ serviceInformation.managementApiEndpoint = prefixUrlProtocol(serviceInformation.managementApiEndpoint);
923
955
  miscConfig.openUrl = miscConfig.openUrl
924
956
  ? prefixUrlProtocol(miscConfig.openUrl)
925
957
  : miscConfig.openUrl;
926
- return generateProject(widgetConfig, deployConfig, miscConfig)
958
+ return generateProject(widgetConfig, serviceInformation, miscConfig)
927
959
  .then(() => green("\nThe custom widget’s code scaffold has been successfully generated.\n"))
928
960
  .catch(console.error);
929
961
  }
@@ -3,5 +3,6 @@ const {deployNodeJS} = require("@azure/api-management-custom-widgets-tools")
3
3
  const serviceInformation = {{&configDeploy}}
4
4
  const name = "{{name}}"
5
5
  const fallbackConfigPath = "./static/config.msapim.json"
6
+ const config = {{&configAdditional}}
6
7
 
7
- deployNodeJS(serviceInformation, name, fallbackConfigPath)
8
+ deployNodeJS(serviceInformation, name, fallbackConfigPath, config)
@@ -47,6 +47,7 @@ body {
47
47
  padding: 9px 50px;
48
48
  background-color: rgba(254, 213, 60, 1);
49
49
  border-radius: 3px;
50
+ cursor: pointer;
50
51
  }
51
52
  }
52
53
 
@@ -10,18 +10,17 @@
10
10
  "deploy": "npm run build && node deploy.js"
11
11
  },
12
12
  "dependencies": {
13
- "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.1",
13
+ "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.2",
14
14
  "react": "^18.2.0",
15
- "react-dom": "^18.2.0",
16
- "react-helmet-async": "^1.3.0"
15
+ "react-dom": "^18.2.0"
17
16
  },
18
17
  "devDependencies": {
19
- "@types/react": "^18.0.15",
18
+ "@types/react": "^18.0.17",
20
19
  "@types/react-dom": "^18.0.6",
21
- "@vitejs/plugin-react": "^2.0.0",
20
+ "@vitejs/plugin-react": "^2.0.1",
22
21
  "prettier": "^2.7.1",
23
- "sass": "^1.53.0",
22
+ "sass": "^1.54.4",
24
23
  "typescript": "^4.7.4",
25
- "vite": "^3.0.0"
24
+ "vite": "^3.0.7"
26
25
  }
27
26
  }
@@ -14,7 +14,7 @@ const App = () => {
14
14
  return
15
15
  }
16
16
 
17
- request(`/subscriptions/000/resourceGroups/000/providers/Microsoft.ApiManagement/service/000/users/${userId}`)
17
+ request(`/users/${userId}`)
18
18
  .then(e => e.json())
19
19
  .then(({properties}) => setDefaultEmail(properties.email))
20
20
  .catch(e => {
@@ -20,6 +20,16 @@ export const SecretsContext = React.createContext<Secrets>({
20
20
  userId: "",
21
21
  apiVersion: "",
22
22
  managementApiUrl: "",
23
+ parentLocation: {
24
+ host: "",
25
+ hostname: "",
26
+ href: "",
27
+ origin: "",
28
+ pathname: "",
29
+ port: "",
30
+ protocol: "",
31
+ search: "",
32
+ },
23
33
  })
24
34
  export const SecretsProvider: React.FC<{children?: React.ReactNode; targetModule: TargetModule}> = (
25
35
  {children, targetModule},
@@ -1,5 +1,5 @@
1
1
  import {defineConfig} from "vite"
2
- import react from '@vitejs/plugin-react'
2
+ import react from "@vitejs/plugin-react"
3
3
 
4
4
  // https://vitejs.dev/config/
5
5
  export default defineConfig(() => ({
@@ -10,12 +10,12 @@
10
10
  "deploy": "npm run build && node deploy.js"
11
11
  },
12
12
  "dependencies": {
13
- "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.1"
13
+ "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.2"
14
14
  },
15
15
  "devDependencies": {
16
- "prettier": "^2.5.1",
17
- "sass": "^1.53.0",
18
- "typescript": "^4.5.4",
19
- "vite": "^2.8.3"
16
+ "prettier": "^2.7.1",
17
+ "sass": "^1.54.4",
18
+ "typescript": "^4.7.4",
19
+ "vite": "^3.0.7"
20
20
  }
21
21
  }
@@ -14,7 +14,7 @@
14
14
  const appInstance = new App(secrets)
15
15
  if (!secrets.userId) return
16
16
 
17
- appInstance.request(`/subscriptions/000/resourceGroups/000/providers/Microsoft.ApiManagement/service/000/users/${secrets.userId}`)
17
+ appInstance.request(`/users/${secrets.userId}`)
18
18
  .then(e => e.json())
19
19
  .then(({properties}) => {
20
20
  if (properties.email) document.getElementById("email").value = properties.email
@@ -3,7 +3,7 @@
3
3
  "module": "ESNext",
4
4
  "target": "es6",
5
5
  "useDefineForClassFields": true,
6
- "lib": ["ESNext", "ES6", "DOM.Iterable"],
6
+ "lib": ["ESNext", "ES6", "DOM", "DOM.Iterable"],
7
7
  "moduleResolution": "Node",
8
8
  "strict": true,
9
9
  "sourceMap": true,
@@ -10,14 +10,14 @@
10
10
  "deploy": "npm run build && node deploy.js"
11
11
  },
12
12
  "dependencies": {
13
- "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.1",
13
+ "@azure/api-management-custom-widgets-tools": "^1.0.0-beta.2",
14
14
  "vue": "^3.2.37"
15
15
  },
16
16
  "devDependencies": {
17
- "@vitejs/plugin-vue": "^3.0.1",
17
+ "@vitejs/plugin-vue": "^3.0.3",
18
18
  "prettier": "^2.7.1",
19
- "sass": "^1.53.0",
19
+ "sass": "^1.54.4",
20
20
  "typescript": "^4.7.4",
21
- "vite": "^3.0.3"
21
+ "vite": "^3.0.7"
22
22
  }
23
23
  }
@@ -50,7 +50,7 @@ export default {
50
50
  return
51
51
  }
52
52
 
53
- request(`/subscriptions/000/resourceGroups/000/providers/Microsoft.ApiManagement/service/000/users/${secrets.userId}`)
53
+ request(`/users/${secrets.userId}`)
54
54
  .then(e => e.json())
55
55
  .then(({properties}) => this.defaultEmail = properties.email)
56
56
  .catch(e => {
package/dist/index.js CHANGED
@@ -1,17 +1,10 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var path = require('path');
6
4
  var fs = require('fs');
7
5
  var glob = require('glob');
8
6
  var mustache = require('mustache');
9
7
 
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
-
12
- var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
13
- var mustache__default = /*#__PURE__*/_interopDefaultLegacy(mustache);
14
-
15
8
  // Copyright (c) Microsoft Corporation.
16
9
  // Licensed under the MIT license.
17
10
  /**
@@ -42,23 +35,22 @@ const displayNameToName = (displayName) => encodeURIComponent(displayName
42
35
  const widgetFolderName = (name) => `azure-api-management-widget-${name}`;
43
36
 
44
37
  // Copyright (c) Microsoft Corporation.
38
+ // Licensed under the MIT license.
45
39
  async function getTemplates(template) {
46
40
  const sharedFiles = await getFiles(path.join(__dirname, "templates", "_shared", "**", "**", "*.*"));
47
41
  const templateFiles = await getFiles(path.join(__dirname, "templates", template, "**", "**", "*.*"));
48
42
  return [...sharedFiles, ...templateFiles];
49
43
  }
50
44
  async function getFiles(path) {
51
- return new Promise((resolve, reject) => {
52
- glob__default["default"](path, { dot: true }, (error, matches) => {
53
- if (error) {
54
- reject(error);
55
- }
56
- resolve(matches);
57
- });
58
- });
45
+ // Starting from glob v8 `\` is only used as an escape character, and never as a path separator in glob patterns.
46
+ // Glob pattern paths must use forward-slashes as path separators.
47
+ // See https://github.com/isaacs/node-glob/blob/af57da21c7722bb6edb687ccd4ad3b99d3e7a333/changelog.md#80
48
+ const normalizedPath = path.replace(/\\/g, "/");
49
+ return glob.glob(normalizedPath, { dot: true });
59
50
  }
60
51
 
61
52
  // Copyright (c) Microsoft Corporation.
53
+ // Licensed under the MIT license.
62
54
  const templateSuffix = ".mustache";
63
55
  /**
64
56
  * Generates a scaffold project of Custom widget for API Managements' Dev Portal.
@@ -68,7 +60,7 @@ const templateSuffix = ".mustache";
68
60
  * @param options - JSON object with other data, which will not be stored in the DevPortal.
69
61
  */
70
62
  async function generateProject(widgetConfig, deploymentConfig, options = {}) {
71
- const { openUrl } = options;
63
+ const { openUrl, configAdvancedTenantId, configAdvancedRedirectUri } = options;
72
64
  const openUrlParsed = openUrl ? new URL(openUrl) : null;
73
65
  if (openUrlParsed) {
74
66
  openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));
@@ -78,16 +70,26 @@ async function generateProject(widgetConfig, deploymentConfig, options = {}) {
78
70
  port: OVERRIDE_DEFAULT_PORT,
79
71
  open: openUrlParsed ? openUrlParsed.toString() : true,
80
72
  };
73
+ const configAdditional = {
74
+ interactiveBrowserCredentialOptions: { redirectUri: "http://localhost:1337" },
75
+ };
76
+ if (configAdvancedTenantId) {
77
+ configAdditional.interactiveBrowserCredentialOptions.tenantId = configAdvancedTenantId;
78
+ }
79
+ if (configAdvancedRedirectUri) {
80
+ configAdditional.interactiveBrowserCredentialOptions.redirectUri = configAdvancedRedirectUri;
81
+ }
81
82
  const renderTemplate = async (file) => {
82
83
  const isTemplate = file.endsWith(templateSuffix);
83
84
  const encoding = file.endsWith(".ttf") ? "binary" : "utf8";
84
85
  let fileData = await fs.promises.readFile(file, { encoding });
85
86
  if (isTemplate) {
86
- fileData = mustache__default["default"].render(fileData, {
87
+ fileData = mustache.render(fileData, {
87
88
  name,
88
89
  displayName: widgetConfig.displayName,
89
90
  config: JSON.stringify(Object.assign(Object.assign({}, widgetConfig), { name }), null, "\t"),
90
91
  configDeploy: JSON.stringify(deploymentConfig, null, "\t"),
92
+ configAdditional: JSON.stringify(configAdditional, null, "\t"),
91
93
  serverSettings: JSON.stringify(serverSettings, null, "\t"),
92
94
  });
93
95
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/scaffolding.ts","../src/getTemplates.ts","../src/generateProject.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Unique identifier under which is specified which port to use for injecting locally hosted custom widget to a running DevPortal instance.\n */\nexport const OVERRIDE_PORT_KEY = \"MS_APIM_CW_localhost_port\";\n/**\n * Default port for running local dev server on.\n */\nexport const OVERRIDE_DEFAULT_PORT = 3000;\n\n/** All supported technologies to scaffold a widget in. */\nexport type ScaffoldTech = \"typescript\" | \"react\" | \"vue\";\n\n/** List of all supported technologies to scaffold a widget in. */\nexport const TECHNOLOGIES: ScaffoldTech[] = [\"typescript\", \"react\", \"vue\"];\n\n/** Main data which DevPortal needs for every custom widget. */\nexport interface WidgetConfig {\n /** Name of the custom widget which is displayed in DevPortal. */\n displayName: string;\n /** Technology to use to scaffold the widget. */\n technology: ScaffoldTech;\n /** Optional URL for a custom icon, which will be displayed in DevPortal widget list. */\n iconUrl?: string;\n}\n\n/** Data needed for deployment. */\nexport interface DeploymentConfig {\n /** Management API endpoint to use (e.g. management.azure.com). */\n managementApiEndpoint: string;\n /** resourceId of your APIM service, must be in this format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<service-name> */\n resourceId: string;\n /** optional override which API version to use during deployment */\n apiVersion?: string;\n}\n\n/** Miscellaneous data for scaffolding of a custom widget which will not be stored in DevPortal. */\nexport interface Options {\n /** The URL to open after development server of the widget is started (URL of your Developer Portal). If you don't want to use this feature, set it to `false`. If you want to open just the widget page, set it to `true`. */\n openUrl?: string;\n}\n\nexport type Configs = WidgetConfig | DeploymentConfig | Options;\n\n/**\n * Converts user defined name of a custom widget to a unique ID, which is in context of Dev Portal known as \"name\".\n *\n * @param displayName - User defined name of the custom widget.\n */\nexport const displayNameToName = (displayName: string): string =>\n encodeURIComponent(\n displayName\n .normalize(\"NFD\")\n .toLowerCase()\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n );\n\n/**\n * Returns name of the folder for widget project.\n *\n * @param name - name of the widget\n */\nexport const widgetFolderName = (name: string): string => `azure-api-management-widget-${name}`;\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { ScaffoldTech } from \"./scaffolding\";\nimport glob from \"glob\";\nimport { join as pathJoin } from \"path\";\n\nexport async function getTemplates(template: ScaffoldTech): Promise<string[]> {\n const sharedFiles = await getFiles(\n pathJoin(__dirname, \"templates\", \"_shared\", \"**\", \"**\", \"*.*\")\n );\n const templateFiles = await getFiles(\n pathJoin(__dirname, \"templates\", template, \"**\", \"**\", \"*.*\")\n );\n return [...sharedFiles, ...templateFiles];\n}\n\nasync function getFiles(path: string): Promise<string[]> {\n return new Promise((resolve, reject) => {\n glob(path, { dot: true }, (error, matches) => {\n if (error) {\n reject(error);\n }\n resolve(matches);\n });\n });\n}\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n DeploymentConfig,\n OVERRIDE_DEFAULT_PORT,\n OVERRIDE_PORT_KEY,\n Options,\n WidgetConfig,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nimport { join as joinPath, parse as parsePath } from \"path\";\nimport { promises as fs } from \"fs\";\nimport { getTemplates } from \"./getTemplates\";\nimport mustache from \"mustache\";\n\nconst templateSuffix = \".mustache\";\n\n/**\n * Generates a scaffold project of Custom widget for API Managements' Dev Portal.\n *\n * @param widgetConfig - JSON object with data required by DevPortal to handle a widget integration.\n * @param deploymentConfig - JSON object with data for deployment.\n * @param options - JSON object with other data, which will not be stored in the DevPortal.\n */\nexport async function generateProject(\n widgetConfig: WidgetConfig,\n deploymentConfig: DeploymentConfig,\n options: Options = {}\n): Promise<void> {\n const { openUrl } = options;\n const openUrlParsed = openUrl ? new URL(openUrl) : null;\n if (openUrlParsed) {\n openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));\n }\n\n const name = displayNameToName(widgetConfig.displayName);\n const serverSettings = {\n port: OVERRIDE_DEFAULT_PORT,\n open: openUrlParsed ? openUrlParsed.toString() : true,\n };\n\n const renderTemplate = async (file: string): Promise<void> => {\n const isTemplate = file.endsWith(templateSuffix);\n const encoding = file.endsWith(\".ttf\") ? \"binary\" : \"utf8\";\n let fileData = await fs.readFile(file, { encoding });\n if (isTemplate) {\n fileData = mustache.render(fileData, {\n name,\n displayName: widgetConfig.displayName,\n config: JSON.stringify({ ...widgetConfig, name }, null, \"\\t\"),\n configDeploy: JSON.stringify(deploymentConfig, null, \"\\t\"),\n serverSettings: JSON.stringify(serverSettings, null, \"\\t\"),\n });\n }\n\n let relativePath = file;\n if (__dirname.includes(\"\\\\\")) {\n relativePath = relativePath.replace(/\\//g, \"\\\\\");\n }\n relativePath = relativePath\n .replace(joinPath(__dirname, \"templates\", \"_shared\"), \"\")\n .replace(joinPath(__dirname, \"templates\", widgetConfig.technology), \"\")\n .replace(templateSuffix, \"\");\n const newFilePath = joinPath(process.cwd(), widgetFolderName(name), relativePath);\n const dir = parsePath(newFilePath).dir;\n\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(newFilePath, fileData, { encoding });\n };\n\n const templates = await getTemplates(widgetConfig.technology);\n for (const file of Object.values(templates)) {\n await renderTemplate(file);\n }\n\n return;\n}\n"],"names":["pathJoin","glob","fs","mustache","joinPath","parsePath"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/scaffolding.ts","../src/getTemplates.ts","../src/generateProject.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Unique identifier under which is specified which port to use for injecting locally hosted custom widget to a running DevPortal instance.\n */\nexport const OVERRIDE_PORT_KEY = \"MS_APIM_CW_localhost_port\";\n/**\n * Default port for running local dev server on.\n */\nexport const OVERRIDE_DEFAULT_PORT = 3000;\n\n/** All supported technologies to scaffold a widget in. */\nexport type ScaffoldTech = \"typescript\" | \"react\" | \"vue\";\n\n/** List of all supported technologies to scaffold a widget in. */\nexport const TECHNOLOGIES: ScaffoldTech[] = [\"typescript\", \"react\", \"vue\"];\n\n/** Main data which DevPortal needs for every custom widget. */\nexport interface WidgetConfig {\n /** Name of the custom widget which is displayed in DevPortal. */\n displayName: string;\n /** Technology to use to scaffold the widget. */\n technology: ScaffoldTech;\n /** Optional URL for a custom icon, which will be displayed in DevPortal widget list. */\n iconUrl?: string;\n}\n\n/** Data needed for deployment. */\nexport interface ServiceInformation {\n /** Management API endpoint to use (e.g. management.azure.com). */\n managementApiEndpoint: string;\n /** resourceId of your APIM service, must be in this format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<service-name> */\n resourceId: string;\n /** optional override which API version to use during deployment */\n apiVersion?: string;\n}\n\n/** Miscellaneous data for scaffolding of a custom widget which will not be stored in DevPortal. */\nexport interface Options {\n /** The URL to open after development server of the widget is started (URL of your Developer Portal). If you don't want to use this feature, set it to `false`. If you want to open just the widget page, set it to `true`. */\n openUrl?: string;\n /** advance configuration option for the deploy function - tenant ID for InteractiveBrowserCredentialNodeOptions */\n configAdvancedTenantId?: string;\n /** advance configuration option for the deploy function - redirect URI for InteractiveBrowserCredentialNodeOptions */\n configAdvancedRedirectUri?: string;\n}\n\nexport type Configs = WidgetConfig | ServiceInformation | Options;\n\n/**\n * Converts user defined name of a custom widget to a unique ID, which is in context of Dev Portal known as \"name\".\n *\n * @param displayName - User defined name of the custom widget.\n */\nexport const displayNameToName = (displayName: string): string =>\n encodeURIComponent(\n displayName\n .normalize(\"NFD\")\n .toLowerCase()\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n );\n\n/**\n * Returns name of the folder for widget project.\n *\n * @param name - name of the widget\n */\nexport const widgetFolderName = (name: string): string => `azure-api-management-widget-${name}`;\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { ScaffoldTech } from \"./scaffolding\";\nimport { glob } from \"glob\";\nimport { join as pathJoin } from \"path\";\n\nexport async function getTemplates(template: ScaffoldTech): Promise<string[]> {\n const sharedFiles = await getFiles(\n pathJoin(__dirname, \"templates\", \"_shared\", \"**\", \"**\", \"*.*\")\n );\n const templateFiles = await getFiles(\n pathJoin(__dirname, \"templates\", template, \"**\", \"**\", \"*.*\")\n );\n return [...sharedFiles, ...templateFiles];\n}\n\nasync function getFiles(path: string): Promise<string[]> {\n // Starting from glob v8 `\\` is only used as an escape character, and never as a path separator in glob patterns.\n // Glob pattern paths must use forward-slashes as path separators.\n // See https://github.com/isaacs/node-glob/blob/af57da21c7722bb6edb687ccd4ad3b99d3e7a333/changelog.md#80\n const normalizedPath = path.replace(/\\\\/g, \"/\");\n return glob(normalizedPath, { dot: true });\n}\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n ServiceInformation,\n OVERRIDE_DEFAULT_PORT,\n OVERRIDE_PORT_KEY,\n Options,\n WidgetConfig,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nimport { join as joinPath, parse as parsePath } from \"path\";\nimport { promises as fs } from \"fs\";\nimport { getTemplates } from \"./getTemplates\";\nimport mustache from \"mustache\";\n\nconst templateSuffix = \".mustache\";\n\n/**\n * Generates a scaffold project of Custom widget for API Managements' Dev Portal.\n *\n * @param widgetConfig - JSON object with data required by DevPortal to handle a widget integration.\n * @param deploymentConfig - JSON object with data for deployment.\n * @param options - JSON object with other data, which will not be stored in the DevPortal.\n */\nexport async function generateProject(\n widgetConfig: WidgetConfig,\n deploymentConfig: ServiceInformation,\n options: Options = {}\n): Promise<void> {\n const { openUrl, configAdvancedTenantId, configAdvancedRedirectUri } = options;\n const openUrlParsed = openUrl ? new URL(openUrl) : null;\n if (openUrlParsed) {\n openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));\n }\n\n const name = displayNameToName(widgetConfig.displayName);\n const serverSettings = {\n port: OVERRIDE_DEFAULT_PORT,\n open: openUrlParsed ? openUrlParsed.toString() : true,\n };\n\n const configAdditional = {\n interactiveBrowserCredentialOptions: { redirectUri: \"http://localhost:1337\" } as {\n redirectUri: string;\n tenantId?: string;\n },\n };\n if (configAdvancedTenantId) {\n configAdditional.interactiveBrowserCredentialOptions.tenantId = configAdvancedTenantId;\n }\n if (configAdvancedRedirectUri) {\n configAdditional.interactiveBrowserCredentialOptions.redirectUri = configAdvancedRedirectUri;\n }\n\n const renderTemplate = async (file: string): Promise<void> => {\n const isTemplate = file.endsWith(templateSuffix);\n const encoding = file.endsWith(\".ttf\") ? \"binary\" : \"utf8\";\n let fileData = await fs.readFile(file, { encoding });\n if (isTemplate) {\n fileData = mustache.render(fileData, {\n name,\n displayName: widgetConfig.displayName,\n config: JSON.stringify({ ...widgetConfig, name }, null, \"\\t\"),\n configDeploy: JSON.stringify(deploymentConfig, null, \"\\t\"),\n configAdditional: JSON.stringify(configAdditional, null, \"\\t\"),\n serverSettings: JSON.stringify(serverSettings, null, \"\\t\"),\n });\n }\n\n let relativePath = file;\n if (__dirname.includes(\"\\\\\")) {\n relativePath = relativePath.replace(/\\//g, \"\\\\\");\n }\n relativePath = relativePath\n .replace(joinPath(__dirname, \"templates\", \"_shared\"), \"\")\n .replace(joinPath(__dirname, \"templates\", widgetConfig.technology), \"\")\n .replace(templateSuffix, \"\");\n const newFilePath = joinPath(process.cwd(), widgetFolderName(name), relativePath);\n const dir = parsePath(newFilePath).dir;\n\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(newFilePath, fileData, { encoding });\n };\n\n const templates = await getTemplates(widgetConfig.technology);\n for (const file of Object.values(templates)) {\n await renderTemplate(file);\n }\n\n return;\n}\n"],"names":["pathJoin","glob","fs","joinPath","parsePath"],"mappings":"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"}
@@ -6,10 +6,12 @@ export const fieldIdToName = {
6
6
  displayName: "Widget display name",
7
7
  technology: "Technology",
8
8
  iconUrl: "iconUrl",
9
- resourceId: "Azure API Management resource ID",
9
+ resourceId: "Azure API Management resource ID (following format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<api-management service-name>)",
10
10
  managementApiEndpoint: "Management API hostname",
11
11
  apiVersion: "Management API version",
12
12
  openUrl: "Developer portal URL",
13
+ configAdvancedTenantId: "Tenant ID",
14
+ configAdvancedRedirectUri: "Redirect URI",
13
15
  };
14
16
  export const prefixUrlProtocol = (value) => /https?:\/\//.test(value) ? value : `https://${value}`;
15
17
  const validateRequired = (name, msg = `The “${name}” parameter is required.`) => (input) => (input != null && input !== "") || msg;
@@ -47,12 +49,7 @@ export const validateDeployConfig = {
47
49
  ? true
48
50
  : "Resource ID needs to be a valid Azure resource ID. For example, subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/contoso-group/providers/Microsoft.ApiManagement/service/contoso-apis.";
49
51
  },
50
- managementApiEndpoint: (input) => {
51
- const required = validateRequired(fieldIdToName.managementApiEndpoint)(input);
52
- if (required !== true)
53
- return required;
54
- return validateUrl(fieldIdToName.managementApiEndpoint)(input);
55
- },
52
+ managementApiEndpoint: (input) => validateRequired(fieldIdToName.managementApiEndpoint)(input),
56
53
  };
57
54
  export const validateMiscConfig = {
58
55
  openUrl: (input) => {
@@ -60,6 +57,14 @@ export const validateMiscConfig = {
60
57
  return true;
61
58
  return validateUrl(fieldIdToName.openUrl)(input);
62
59
  },
60
+ configAdvancedTenantId: () => {
61
+ return true;
62
+ },
63
+ configAdvancedRedirectUri: (input) => {
64
+ if (!input)
65
+ return true;
66
+ return validateUrl(fieldIdToName.openUrl)(input);
67
+ },
63
68
  };
64
69
  export const promptWidgetConfig = (partial) => inquirer.prompt([
65
70
  {
@@ -79,7 +84,7 @@ export const promptWidgetConfig = (partial) => inquirer.prompt([
79
84
  ],
80
85
  },
81
86
  ], partial);
82
- export const promptDeployConfig = (partial) => inquirer.prompt([
87
+ export const promptServiceInformation = (partial) => inquirer.prompt([
83
88
  {
84
89
  name: "resourceId",
85
90
  type: "input",
@@ -88,9 +93,16 @@ export const promptDeployConfig = (partial) => inquirer.prompt([
88
93
  },
89
94
  {
90
95
  name: "managementApiEndpoint",
91
- type: "input",
96
+ type: "list",
92
97
  message: fieldIdToName.managementApiEndpoint,
93
- default: "management.azure.com",
98
+ choices: [
99
+ {
100
+ name: "management.azure.com (if you're not sure what to select, use this option)",
101
+ value: "management.azure.com",
102
+ },
103
+ { name: "management.usgovcloudapi.net", value: "management.usgovcloudapi.net" },
104
+ { name: "management.chinacloudapi.cn", value: "management.chinacloudapi.cn" },
105
+ ],
94
106
  transformer: prefixUrlProtocol,
95
107
  validate: validateDeployConfig.managementApiEndpoint,
96
108
  },
@@ -109,5 +121,19 @@ export const promptMiscConfig = (partial) => inquirer.prompt([
109
121
  transformer: prefixUrlProtocol,
110
122
  validate: validateMiscConfig.openUrl,
111
123
  },
124
+ {
125
+ name: "configAdvancedTenantId",
126
+ type: "input",
127
+ message: fieldIdToName.configAdvancedTenantId +
128
+ " to be used in Azure Identity InteractiveBrowserCredential class (optional)",
129
+ validate: validateMiscConfig.openUrl,
130
+ },
131
+ {
132
+ name: "configAdvancedRedirectUri",
133
+ type: "input",
134
+ message: fieldIdToName.configAdvancedRedirectUri +
135
+ " to be used in Azure Identity InteractiveBrowserCredential class (optional; default is http://localhost:1337)",
136
+ validate: validateMiscConfig.openUrl,
137
+ },
112
138
  ], partial);
113
139
  //# sourceMappingURL=execute-configs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute-configs.js","sourceRoot":"","sources":["../../../src/bin/execute-configs.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { Configs, DeploymentConfig, Options, TECHNOLOGIES, WidgetConfig } from \"../scaffolding\";\n\nimport inquirer from \"inquirer\";\n\nexport const fieldIdToName: Record<\n keyof (WidgetConfig & DeploymentConfig & Options) | string,\n string\n> = {\n displayName: \"Widget display name\",\n technology: \"Technology\",\n iconUrl: \"iconUrl\",\n\n resourceId: \"Azure API Management resource ID\",\n managementApiEndpoint: \"Management API hostname\",\n apiVersion: \"Management API version\",\n\n openUrl: \"Developer portal URL\",\n};\n\nexport const prefixUrlProtocol = (value: string): string =>\n /https?:\\/\\//.test(value) ? value : `https://${value}`;\n\nconst validateRequired =\n (name: string, msg: string = `The “${name}” parameter is required.`) =>\n (input: unknown) =>\n (input != null && input !== \"\") || msg;\n\nconst validateUrl =\n (\n name: string,\n msg = (input: string) =>\n `Provided “${name}” parameter value (“${prefixUrlProtocol(\n input\n )}”) isn’t a valid URL. Use the correct URL format, e.g., https://contoso.com.`\n ) =>\n (input: string) => {\n try {\n new URL(prefixUrlProtocol(input));\n return true;\n } catch (e) {\n return msg(prefixUrlProtocol(input));\n }\n };\n\nexport type ReplaceTypesPreserveOptional<T extends Record<any, any>, V> = {\n [Key in keyof T]: T[Key] extends undefined ? V | undefined : V;\n};\n\nexport type ValidateFnc = (input: string) => boolean | string;\nexport type Validate<C extends Configs> = ReplaceTypesPreserveOptional<C, ValidateFnc>;\n\nexport const validateWidgetConfig: Validate<WidgetConfig> = {\n displayName: validateRequired(fieldIdToName.displayName),\n technology: (input) => {\n const required = validateRequired(fieldIdToName.technology)(input);\n if (required !== true) return required;\n\n if (TECHNOLOGIES.includes(input as any)) {\n return true;\n } else {\n return (\n \"Provided “technology” parameter value isn’t correct. Use one of the following: \" +\n TECHNOLOGIES.join(\", \")\n );\n }\n },\n};\n\nexport const validateDeployConfig: Validate<DeploymentConfig> = {\n resourceId: (input) => {\n const required = validateRequired(fieldIdToName.resourceId)(input);\n if (required !== true) return required;\n\n const regex =\n /^\\/?subscriptions\\/[^/]+\\/resourceGroups\\/[^/]+\\/providers\\/Microsoft\\.ApiManagement\\/service\\/[^/]+\\/?$/;\n return input === \"test\" || regex.test(input)\n ? true\n : \"Resource ID needs to be a valid Azure resource ID. For example, subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/contoso-group/providers/Microsoft.ApiManagement/service/contoso-apis.\";\n },\n managementApiEndpoint: (input) => {\n const required = validateRequired(fieldIdToName.managementApiEndpoint)(input);\n if (required !== true) return required;\n\n return validateUrl(fieldIdToName.managementApiEndpoint)(input);\n },\n};\n\nexport const validateMiscConfig: Validate<Options> = {\n openUrl: (input) => {\n if (!input) return true;\n return validateUrl(fieldIdToName.openUrl)(input);\n },\n};\n\nexport const promptWidgetConfig = (partial: Partial<WidgetConfig>): Promise<WidgetConfig> =>\n inquirer.prompt(\n [\n {\n name: \"displayName\",\n type: \"input\",\n message: fieldIdToName.displayName,\n validate: validateWidgetConfig.displayName,\n },\n {\n name: \"technology\",\n type: \"list\",\n message: fieldIdToName.technology,\n choices: [\n { name: \"React\", value: \"react\" },\n { name: \"Vue\", value: \"vue\" },\n { name: \"TypeScript\", value: \"typescript\" },\n ],\n },\n ],\n partial\n );\n\nexport const promptDeployConfig = (partial: Partial<DeploymentConfig>): Promise<DeploymentConfig> =>\n inquirer.prompt(\n [\n {\n name: \"resourceId\",\n type: \"input\",\n message: fieldIdToName.resourceId,\n validate: validateDeployConfig.resourceId,\n },\n {\n name: \"managementApiEndpoint\",\n type: \"input\",\n message: fieldIdToName.managementApiEndpoint, // (e.g., management.azure.com for the public Azure cloud)\n default: \"management.azure.com\",\n transformer: prefixUrlProtocol,\n validate: validateDeployConfig.managementApiEndpoint,\n },\n {\n name: \"apiVersion\",\n type: \"input\",\n message: fieldIdToName.apiVersion + \" (optional; e.g., 2021-08-01)\",\n },\n ],\n partial\n );\n\nexport const promptMiscConfig = (partial: Partial<Options>): Promise<Options> =>\n inquirer.prompt(\n [\n {\n name: \"openUrl\",\n type: \"input\",\n message:\n fieldIdToName.openUrl +\n \" for widget development and testing (optional; e.g., https://contoso.developer.azure-api.net/ or http://localhost:8080)\",\n transformer: prefixUrlProtocol,\n validate: validateMiscConfig.openUrl,\n },\n ],\n partial\n );\n"]}
1
+ {"version":3,"file":"execute-configs.js","sourceRoot":"","sources":["../../../src/bin/execute-configs.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { Configs, ServiceInformation, Options, TECHNOLOGIES, WidgetConfig } from \"../scaffolding\";\n\nimport inquirer from \"inquirer\";\n\nexport const fieldIdToName: Record<\n keyof (WidgetConfig & ServiceInformation & Options) | string,\n string\n> = {\n displayName: \"Widget display name\",\n technology: \"Technology\",\n iconUrl: \"iconUrl\",\n\n resourceId:\n \"Azure API Management resource ID (following format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<api-management service-name>)\",\n managementApiEndpoint: \"Management API hostname\",\n apiVersion: \"Management API version\",\n\n openUrl: \"Developer portal URL\",\n configAdvancedTenantId: \"Tenant ID\",\n configAdvancedRedirectUri: \"Redirect URI\",\n};\n\nexport const prefixUrlProtocol = (value: string): string =>\n /https?:\\/\\//.test(value) ? value : `https://${value}`;\n\nconst validateRequired =\n (name: string, msg: string = `The “${name}” parameter is required.`) =>\n (input: unknown) =>\n (input != null && input !== \"\") || msg;\n\nconst validateUrl =\n (\n name: string,\n msg = (input: string) =>\n `Provided “${name}” parameter value (“${prefixUrlProtocol(\n input\n )}”) isn’t a valid URL. Use the correct URL format, e.g., https://contoso.com.`\n ) =>\n (input: string) => {\n try {\n new URL(prefixUrlProtocol(input));\n return true;\n } catch (e) {\n return msg(prefixUrlProtocol(input));\n }\n };\n\nexport type ReplaceTypesPreserveOptional<T extends Record<any, any>, V> = {\n [Key in keyof T]: T[Key] extends undefined ? V | undefined : V;\n};\n\nexport type ValidateFnc = (input: string) => boolean | string;\nexport type Validate<C extends Configs> = ReplaceTypesPreserveOptional<C, ValidateFnc>;\n\nexport const validateWidgetConfig: Validate<WidgetConfig> = {\n displayName: validateRequired(fieldIdToName.displayName),\n technology: (input) => {\n const required = validateRequired(fieldIdToName.technology)(input);\n if (required !== true) return required;\n\n if (TECHNOLOGIES.includes(input as any)) {\n return true;\n } else {\n return (\n \"Provided “technology” parameter value isn’t correct. Use one of the following: \" +\n TECHNOLOGIES.join(\", \")\n );\n }\n },\n};\n\nexport const validateDeployConfig: Validate<ServiceInformation> = {\n resourceId: (input) => {\n const required = validateRequired(fieldIdToName.resourceId)(input);\n if (required !== true) return required;\n\n const regex =\n /^\\/?subscriptions\\/[^/]+\\/resourceGroups\\/[^/]+\\/providers\\/Microsoft\\.ApiManagement\\/service\\/[^/]+\\/?$/;\n return input === \"test\" || regex.test(input)\n ? true\n : \"Resource ID needs to be a valid Azure resource ID. For example, subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/contoso-group/providers/Microsoft.ApiManagement/service/contoso-apis.\";\n },\n managementApiEndpoint: (input) => validateRequired(fieldIdToName.managementApiEndpoint)(input),\n};\n\nexport const validateMiscConfig: Validate<Options> = {\n openUrl: (input) => {\n if (!input) return true;\n return validateUrl(fieldIdToName.openUrl)(input);\n },\n configAdvancedTenantId: () => {\n return true;\n },\n configAdvancedRedirectUri: (input) => {\n if (!input) return true;\n return validateUrl(fieldIdToName.openUrl)(input);\n },\n};\n\nexport const promptWidgetConfig = (partial: Partial<WidgetConfig>): Promise<WidgetConfig> =>\n inquirer.prompt(\n [\n {\n name: \"displayName\",\n type: \"input\",\n message: fieldIdToName.displayName,\n validate: validateWidgetConfig.displayName,\n },\n {\n name: \"technology\",\n type: \"list\",\n message: fieldIdToName.technology,\n choices: [\n { name: \"React\", value: \"react\" },\n { name: \"Vue\", value: \"vue\" },\n { name: \"TypeScript\", value: \"typescript\" },\n ],\n },\n ],\n partial\n );\n\nexport const promptServiceInformation = (\n partial: Partial<ServiceInformation>\n): Promise<ServiceInformation> =>\n inquirer.prompt(\n [\n {\n name: \"resourceId\",\n type: \"input\",\n message: fieldIdToName.resourceId,\n validate: validateDeployConfig.resourceId,\n },\n {\n name: \"managementApiEndpoint\",\n type: \"list\",\n message: fieldIdToName.managementApiEndpoint,\n choices: [\n {\n name: \"management.azure.com (if you're not sure what to select, use this option)\",\n value: \"management.azure.com\",\n },\n { name: \"management.usgovcloudapi.net\", value: \"management.usgovcloudapi.net\" },\n { name: \"management.chinacloudapi.cn\", value: \"management.chinacloudapi.cn\" },\n ],\n transformer: prefixUrlProtocol,\n validate: validateDeployConfig.managementApiEndpoint,\n },\n {\n name: \"apiVersion\",\n type: \"input\",\n message: fieldIdToName.apiVersion + \" (optional; e.g., 2021-08-01)\",\n },\n ],\n partial\n );\n\nexport const promptMiscConfig = (partial: Partial<Options>): Promise<Options> =>\n inquirer.prompt(\n [\n {\n name: \"openUrl\",\n type: \"input\",\n message:\n fieldIdToName.openUrl +\n \" for widget development and testing (optional; e.g., https://contoso.developer.azure-api.net/ or http://localhost:8080)\",\n transformer: prefixUrlProtocol,\n validate: validateMiscConfig.openUrl,\n },\n {\n name: \"configAdvancedTenantId\",\n type: \"input\",\n message:\n fieldIdToName.configAdvancedTenantId +\n \" to be used in Azure Identity InteractiveBrowserCredential class (optional)\",\n validate: validateMiscConfig.openUrl,\n },\n {\n name: \"configAdvancedRedirectUri\",\n type: \"input\",\n message:\n fieldIdToName.configAdvancedRedirectUri +\n \" to be used in Azure Identity InteractiveBrowserCredential class (optional; default is http://localhost:1337)\",\n validate: validateMiscConfig.openUrl,\n },\n ],\n partial\n );\n"]}
@@ -2,7 +2,7 @@
2
2
  // Copyright (c) Microsoft Corporation.
3
3
  // Licensed under the MIT license.
4
4
  import { buildGetConfig } from "./execute-helpers";
5
- import { prefixUrlProtocol, promptDeployConfig, promptMiscConfig, promptWidgetConfig, validateDeployConfig, validateMiscConfig, validateWidgetConfig, } from "./execute-configs";
5
+ import { prefixUrlProtocol, promptServiceInformation, promptMiscConfig, promptWidgetConfig, validateDeployConfig, validateMiscConfig, validateWidgetConfig, } from "./execute-configs";
6
6
  import chalk from "chalk";
7
7
  import { generateProject } from "../generateProject";
8
8
  const log = console.log;
@@ -16,23 +16,23 @@ async function main() {
16
16
  white("Specify the custom widget configuration.");
17
17
  const widgetConfig = await getConfig(promptWidgetConfig, validateWidgetConfig);
18
18
  white("Specify the Azure API Management service configuration.");
19
- const deployConfig = await getConfig(promptDeployConfig, validateDeployConfig);
19
+ const serviceInformation = await getConfig(promptServiceInformation, validateDeployConfig);
20
20
  white("Specify other options");
21
21
  const miscConfig = await getConfig(promptMiscConfig, validateMiscConfig);
22
- if (deployConfig.resourceId[0] === "/") {
23
- deployConfig.resourceId = deployConfig.resourceId.slice(1);
22
+ if (serviceInformation.resourceId[0] === "/") {
23
+ serviceInformation.resourceId = serviceInformation.resourceId.slice(1);
24
24
  }
25
- if (deployConfig.resourceId.slice(-1) === "/") {
26
- deployConfig.resourceId = deployConfig.resourceId.slice(0, -1);
25
+ if (serviceInformation.resourceId.slice(-1) === "/") {
26
+ serviceInformation.resourceId = serviceInformation.resourceId.slice(0, -1);
27
27
  }
28
- if (deployConfig.apiVersion === "") {
29
- delete deployConfig.apiVersion;
28
+ if (serviceInformation.apiVersion === "") {
29
+ delete serviceInformation.apiVersion;
30
30
  }
31
- deployConfig.managementApiEndpoint = prefixUrlProtocol(deployConfig.managementApiEndpoint);
31
+ serviceInformation.managementApiEndpoint = prefixUrlProtocol(serviceInformation.managementApiEndpoint);
32
32
  miscConfig.openUrl = miscConfig.openUrl
33
33
  ? prefixUrlProtocol(miscConfig.openUrl)
34
34
  : miscConfig.openUrl;
35
- return generateProject(widgetConfig, deployConfig, miscConfig)
35
+ return generateProject(widgetConfig, serviceInformation, miscConfig)
36
36
  .then(() => green("\nThe custom widget’s code scaffold has been successfully generated.\n"))
37
37
  .catch(console.error);
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/bin/execute.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { Log, buildGetConfig } from \"./execute-helpers\";\nimport {\n prefixUrlProtocol,\n promptDeployConfig,\n promptMiscConfig,\n promptWidgetConfig,\n validateDeployConfig,\n validateMiscConfig,\n validateWidgetConfig,\n} from \"./execute-configs\";\n\nimport chalk from \"chalk\";\nimport { generateProject } from \"../generateProject\";\n\nconst log = console.log;\nconst white: Log = (msg) => log(chalk.white(msg));\nconst green: Log = (msg) => log(chalk.green(msg));\nconst red: Log = (msg) => log(chalk.red(msg));\nconst gray: Log = (msg) => log(chalk.gray(msg));\n\nasync function main(): Promise<void> {\n green(\n \"\\nThis tool generates code scaffold for custom widgets in the Azure API Management’s developer portal. Learn more at https://aka.ms/apimdocs/portal/customwidgets.\\n\"\n );\n\n const getConfig = buildGetConfig(gray, red);\n\n white(\"Specify the custom widget configuration.\");\n const widgetConfig = await getConfig(promptWidgetConfig, validateWidgetConfig);\n white(\"Specify the Azure API Management service configuration.\");\n const deployConfig = await getConfig(promptDeployConfig, validateDeployConfig);\n white(\"Specify other options\");\n const miscConfig = await getConfig(promptMiscConfig, validateMiscConfig);\n\n if (deployConfig.resourceId[0] === \"/\") {\n deployConfig.resourceId = deployConfig.resourceId.slice(1);\n }\n if (deployConfig.resourceId.slice(-1) === \"/\") {\n deployConfig.resourceId = deployConfig.resourceId.slice(0, -1);\n }\n if (deployConfig.apiVersion === \"\") {\n delete deployConfig.apiVersion;\n }\n\n deployConfig.managementApiEndpoint = prefixUrlProtocol(deployConfig.managementApiEndpoint);\n\n miscConfig.openUrl = miscConfig.openUrl\n ? prefixUrlProtocol(miscConfig.openUrl)\n : miscConfig.openUrl;\n\n return generateProject(widgetConfig, deployConfig, miscConfig)\n .then(() => green(\"\\nThe custom widget’s code scaffold has been successfully generated.\\n\"))\n .catch(console.error);\n}\n\nmain()\n .then(() => process.exit(0))\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n"]}
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/bin/execute.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { Log, buildGetConfig } from \"./execute-helpers\";\nimport {\n prefixUrlProtocol,\n promptServiceInformation,\n promptMiscConfig,\n promptWidgetConfig,\n validateDeployConfig,\n validateMiscConfig,\n validateWidgetConfig,\n} from \"./execute-configs\";\n\nimport chalk from \"chalk\";\nimport { generateProject } from \"../generateProject\";\n\nconst log = console.log;\nconst white: Log = (msg) => log(chalk.white(msg));\nconst green: Log = (msg) => log(chalk.green(msg));\nconst red: Log = (msg) => log(chalk.red(msg));\nconst gray: Log = (msg) => log(chalk.gray(msg));\n\nasync function main(): Promise<void> {\n green(\n \"\\nThis tool generates code scaffold for custom widgets in the Azure API Management’s developer portal. Learn more at https://aka.ms/apimdocs/portal/customwidgets.\\n\"\n );\n\n const getConfig = buildGetConfig(gray, red);\n\n white(\"Specify the custom widget configuration.\");\n const widgetConfig = await getConfig(promptWidgetConfig, validateWidgetConfig);\n white(\"Specify the Azure API Management service configuration.\");\n const serviceInformation = await getConfig(promptServiceInformation, validateDeployConfig);\n white(\"Specify other options\");\n const miscConfig = await getConfig(promptMiscConfig, validateMiscConfig);\n\n if (serviceInformation.resourceId[0] === \"/\") {\n serviceInformation.resourceId = serviceInformation.resourceId.slice(1);\n }\n if (serviceInformation.resourceId.slice(-1) === \"/\") {\n serviceInformation.resourceId = serviceInformation.resourceId.slice(0, -1);\n }\n if (serviceInformation.apiVersion === \"\") {\n delete serviceInformation.apiVersion;\n }\n\n serviceInformation.managementApiEndpoint = prefixUrlProtocol(\n serviceInformation.managementApiEndpoint\n );\n\n miscConfig.openUrl = miscConfig.openUrl\n ? prefixUrlProtocol(miscConfig.openUrl)\n : miscConfig.openUrl;\n\n return generateProject(widgetConfig, serviceInformation, miscConfig)\n .then(() => green(\"\\nThe custom widget’s code scaffold has been successfully generated.\\n\"))\n .catch(console.error);\n}\n\nmain()\n .then(() => process.exit(0))\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"generateProject.browser.js","sourceRoot":"","sources":["../../src/generateProject.browser.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAIlC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAA2B,EAC3B,aAA+B,EAC/B,cAAuB,EAAE;IAEzB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;AACtC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { DeploymentConfig, Options, WidgetConfig } from \"./scaffolding\";\n\nexport async function generateProject(\n _widgetConfig: WidgetConfig,\n _deployConfig: DeploymentConfig,\n _miscConfig: Options = {}\n): Promise<void> {\n throw new Error(\"Only for Node.js\");\n}\n"]}
1
+ {"version":3,"file":"generateProject.browser.js","sourceRoot":"","sources":["../../src/generateProject.browser.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAIlC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAA2B,EAC3B,aAAiC,EACjC,cAAuB,EAAE;IAEzB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;AACtC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { ServiceInformation, Options, WidgetConfig } from \"./scaffolding\";\n\nexport async function generateProject(\n _widgetConfig: WidgetConfig,\n _deployConfig: ServiceInformation,\n _miscConfig: Options = {}\n): Promise<void> {\n throw new Error(\"Only for Node.js\");\n}\n"]}
@@ -14,7 +14,7 @@ const templateSuffix = ".mustache";
14
14
  * @param options - JSON object with other data, which will not be stored in the DevPortal.
15
15
  */
16
16
  export async function generateProject(widgetConfig, deploymentConfig, options = {}) {
17
- const { openUrl } = options;
17
+ const { openUrl, configAdvancedTenantId, configAdvancedRedirectUri } = options;
18
18
  const openUrlParsed = openUrl ? new URL(openUrl) : null;
19
19
  if (openUrlParsed) {
20
20
  openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));
@@ -24,6 +24,15 @@ export async function generateProject(widgetConfig, deploymentConfig, options =
24
24
  port: OVERRIDE_DEFAULT_PORT,
25
25
  open: openUrlParsed ? openUrlParsed.toString() : true,
26
26
  };
27
+ const configAdditional = {
28
+ interactiveBrowserCredentialOptions: { redirectUri: "http://localhost:1337" },
29
+ };
30
+ if (configAdvancedTenantId) {
31
+ configAdditional.interactiveBrowserCredentialOptions.tenantId = configAdvancedTenantId;
32
+ }
33
+ if (configAdvancedRedirectUri) {
34
+ configAdditional.interactiveBrowserCredentialOptions.redirectUri = configAdvancedRedirectUri;
35
+ }
27
36
  const renderTemplate = async (file) => {
28
37
  const isTemplate = file.endsWith(templateSuffix);
29
38
  const encoding = file.endsWith(".ttf") ? "binary" : "utf8";
@@ -34,6 +43,7 @@ export async function generateProject(widgetConfig, deploymentConfig, options =
34
43
  displayName: widgetConfig.displayName,
35
44
  config: JSON.stringify(Object.assign(Object.assign({}, widgetConfig), { name }), null, "\t"),
36
45
  configDeploy: JSON.stringify(deploymentConfig, null, "\t"),
46
+ configAdditional: JSON.stringify(configAdditional, null, "\t"),
37
47
  serverSettings: JSON.stringify(serverSettings, null, "\t"),
38
48
  });
39
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generateProject.js","sourceRoot":"","sources":["../../src/generateProject.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n DeploymentConfig,\n OVERRIDE_DEFAULT_PORT,\n OVERRIDE_PORT_KEY,\n Options,\n WidgetConfig,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nimport { join as joinPath, parse as parsePath } from \"path\";\nimport { promises as fs } from \"fs\";\nimport { getTemplates } from \"./getTemplates\";\nimport mustache from \"mustache\";\n\nconst templateSuffix = \".mustache\";\n\n/**\n * Generates a scaffold project of Custom widget for API Managements' Dev Portal.\n *\n * @param widgetConfig - JSON object with data required by DevPortal to handle a widget integration.\n * @param deploymentConfig - JSON object with data for deployment.\n * @param options - JSON object with other data, which will not be stored in the DevPortal.\n */\nexport async function generateProject(\n widgetConfig: WidgetConfig,\n deploymentConfig: DeploymentConfig,\n options: Options = {}\n): Promise<void> {\n const { openUrl } = options;\n const openUrlParsed = openUrl ? new URL(openUrl) : null;\n if (openUrlParsed) {\n openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));\n }\n\n const name = displayNameToName(widgetConfig.displayName);\n const serverSettings = {\n port: OVERRIDE_DEFAULT_PORT,\n open: openUrlParsed ? openUrlParsed.toString() : true,\n };\n\n const renderTemplate = async (file: string): Promise<void> => {\n const isTemplate = file.endsWith(templateSuffix);\n const encoding = file.endsWith(\".ttf\") ? \"binary\" : \"utf8\";\n let fileData = await fs.readFile(file, { encoding });\n if (isTemplate) {\n fileData = mustache.render(fileData, {\n name,\n displayName: widgetConfig.displayName,\n config: JSON.stringify({ ...widgetConfig, name }, null, \"\\t\"),\n configDeploy: JSON.stringify(deploymentConfig, null, \"\\t\"),\n serverSettings: JSON.stringify(serverSettings, null, \"\\t\"),\n });\n }\n\n let relativePath = file;\n if (__dirname.includes(\"\\\\\")) {\n relativePath = relativePath.replace(/\\//g, \"\\\\\");\n }\n relativePath = relativePath\n .replace(joinPath(__dirname, \"templates\", \"_shared\"), \"\")\n .replace(joinPath(__dirname, \"templates\", widgetConfig.technology), \"\")\n .replace(templateSuffix, \"\");\n const newFilePath = joinPath(process.cwd(), widgetFolderName(name), relativePath);\n const dir = parsePath(newFilePath).dir;\n\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(newFilePath, fileData, { encoding });\n };\n\n const templates = await getTemplates(widgetConfig.technology);\n for (const file of Object.values(templates)) {\n await renderTemplate(file);\n }\n\n return;\n}\n"]}
1
+ {"version":3,"file":"generateProject.js","sourceRoot":"","sources":["../../src/generateProject.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n ServiceInformation,\n OVERRIDE_DEFAULT_PORT,\n OVERRIDE_PORT_KEY,\n Options,\n WidgetConfig,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nimport { join as joinPath, parse as parsePath } from \"path\";\nimport { promises as fs } from \"fs\";\nimport { getTemplates } from \"./getTemplates\";\nimport mustache from \"mustache\";\n\nconst templateSuffix = \".mustache\";\n\n/**\n * Generates a scaffold project of Custom widget for API Managements' Dev Portal.\n *\n * @param widgetConfig - JSON object with data required by DevPortal to handle a widget integration.\n * @param deploymentConfig - JSON object with data for deployment.\n * @param options - JSON object with other data, which will not be stored in the DevPortal.\n */\nexport async function generateProject(\n widgetConfig: WidgetConfig,\n deploymentConfig: ServiceInformation,\n options: Options = {}\n): Promise<void> {\n const { openUrl, configAdvancedTenantId, configAdvancedRedirectUri } = options;\n const openUrlParsed = openUrl ? new URL(openUrl) : null;\n if (openUrlParsed) {\n openUrlParsed.searchParams.append(OVERRIDE_PORT_KEY, String(OVERRIDE_DEFAULT_PORT));\n }\n\n const name = displayNameToName(widgetConfig.displayName);\n const serverSettings = {\n port: OVERRIDE_DEFAULT_PORT,\n open: openUrlParsed ? openUrlParsed.toString() : true,\n };\n\n const configAdditional = {\n interactiveBrowserCredentialOptions: { redirectUri: \"http://localhost:1337\" } as {\n redirectUri: string;\n tenantId?: string;\n },\n };\n if (configAdvancedTenantId) {\n configAdditional.interactiveBrowserCredentialOptions.tenantId = configAdvancedTenantId;\n }\n if (configAdvancedRedirectUri) {\n configAdditional.interactiveBrowserCredentialOptions.redirectUri = configAdvancedRedirectUri;\n }\n\n const renderTemplate = async (file: string): Promise<void> => {\n const isTemplate = file.endsWith(templateSuffix);\n const encoding = file.endsWith(\".ttf\") ? \"binary\" : \"utf8\";\n let fileData = await fs.readFile(file, { encoding });\n if (isTemplate) {\n fileData = mustache.render(fileData, {\n name,\n displayName: widgetConfig.displayName,\n config: JSON.stringify({ ...widgetConfig, name }, null, \"\\t\"),\n configDeploy: JSON.stringify(deploymentConfig, null, \"\\t\"),\n configAdditional: JSON.stringify(configAdditional, null, \"\\t\"),\n serverSettings: JSON.stringify(serverSettings, null, \"\\t\"),\n });\n }\n\n let relativePath = file;\n if (__dirname.includes(\"\\\\\")) {\n relativePath = relativePath.replace(/\\//g, \"\\\\\");\n }\n relativePath = relativePath\n .replace(joinPath(__dirname, \"templates\", \"_shared\"), \"\")\n .replace(joinPath(__dirname, \"templates\", widgetConfig.technology), \"\")\n .replace(templateSuffix, \"\");\n const newFilePath = joinPath(process.cwd(), widgetFolderName(name), relativePath);\n const dir = parsePath(newFilePath).dir;\n\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(newFilePath, fileData, { encoding });\n };\n\n const templates = await getTemplates(widgetConfig.technology);\n for (const file of Object.values(templates)) {\n await renderTemplate(file);\n }\n\n return;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
- import glob from "glob";
3
+ import { glob } from "glob";
4
4
  import { join as pathJoin } from "path";
5
5
  export async function getTemplates(template) {
6
6
  const sharedFiles = await getFiles(pathJoin(__dirname, "templates", "_shared", "**", "**", "*.*"));
@@ -8,13 +8,10 @@ export async function getTemplates(template) {
8
8
  return [...sharedFiles, ...templateFiles];
9
9
  }
10
10
  async function getFiles(path) {
11
- return new Promise((resolve, reject) => {
12
- glob(path, { dot: true }, (error, matches) => {
13
- if (error) {
14
- reject(error);
15
- }
16
- resolve(matches);
17
- });
18
- });
11
+ // Starting from glob v8 `\` is only used as an escape character, and never as a path separator in glob patterns.
12
+ // Glob pattern paths must use forward-slashes as path separators.
13
+ // See https://github.com/isaacs/node-glob/blob/af57da21c7722bb6edb687ccd4ad3b99d3e7a333/changelog.md#80
14
+ const normalizedPath = path.replace(/\\/g, "/");
15
+ return glob(normalizedPath, { dot: true });
19
16
  }
20
17
  //# sourceMappingURL=getTemplates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getTemplates.js","sourceRoot":"","sources":["../../src/getTemplates.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAsB;IACvD,MAAM,WAAW,GAAG,MAAM,QAAQ,CAChC,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAC/D,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAClC,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAC9D,CAAC;IACF,OAAO,CAAC,GAAG,WAAW,EAAE,GAAG,aAAa,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY;IAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC3C,IAAI,KAAK,EAAE;gBACT,MAAM,CAAC,KAAK,CAAC,CAAC;aACf;YACD,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { ScaffoldTech } from \"./scaffolding\";\nimport glob from \"glob\";\nimport { join as pathJoin } from \"path\";\n\nexport async function getTemplates(template: ScaffoldTech): Promise<string[]> {\n const sharedFiles = await getFiles(\n pathJoin(__dirname, \"templates\", \"_shared\", \"**\", \"**\", \"*.*\")\n );\n const templateFiles = await getFiles(\n pathJoin(__dirname, \"templates\", template, \"**\", \"**\", \"*.*\")\n );\n return [...sharedFiles, ...templateFiles];\n}\n\nasync function getFiles(path: string): Promise<string[]> {\n return new Promise((resolve, reject) => {\n glob(path, { dot: true }, (error, matches) => {\n if (error) {\n reject(error);\n }\n resolve(matches);\n });\n });\n}\n"]}
1
+ {"version":3,"file":"getTemplates.js","sourceRoot":"","sources":["../../src/getTemplates.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAsB;IACvD,MAAM,WAAW,GAAG,MAAM,QAAQ,CAChC,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAC/D,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAClC,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAC9D,CAAC;IACF,OAAO,CAAC,GAAG,WAAW,EAAE,GAAG,aAAa,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY;IAClC,iHAAiH;IACjH,kEAAkE;IAClE,wGAAwG;IACxG,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { ScaffoldTech } from \"./scaffolding\";\nimport { glob } from \"glob\";\nimport { join as pathJoin } from \"path\";\n\nexport async function getTemplates(template: ScaffoldTech): Promise<string[]> {\n const sharedFiles = await getFiles(\n pathJoin(__dirname, \"templates\", \"_shared\", \"**\", \"**\", \"*.*\")\n );\n const templateFiles = await getFiles(\n pathJoin(__dirname, \"templates\", template, \"**\", \"**\", \"*.*\")\n );\n return [...sharedFiles, ...templateFiles];\n}\n\nasync function getFiles(path: string): Promise<string[]> {\n // Starting from glob v8 `\\` is only used as an escape character, and never as a path separator in glob patterns.\n // Glob pattern paths must use forward-slashes as path separators.\n // See https://github.com/isaacs/node-glob/blob/af57da21c7722bb6edb687ccd4ad3b99d3e7a333/changelog.md#80\n const normalizedPath = path.replace(/\\\\/g, \"/\");\n return glob(normalizedPath, { dot: true });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * @packageDocumentation https://aka.ms/apimdocs/portal/customwidgets\n */\n\nexport {\n OVERRIDE_PORT_KEY,\n OVERRIDE_DEFAULT_PORT,\n TECHNOLOGIES,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nexport { generateProject } from \"./generateProject\";\nexport type {\n WidgetConfig as CustomWidgetCommonConfig,\n DeploymentConfig,\n Options,\n ScaffoldTech,\n} from \"./scaffolding\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * @packageDocumentation https://aka.ms/apimdocs/portal/customwidgets\n */\n\nexport {\n OVERRIDE_PORT_KEY,\n OVERRIDE_DEFAULT_PORT,\n TECHNOLOGIES,\n displayNameToName,\n widgetFolderName,\n} from \"./scaffolding\";\nexport { generateProject } from \"./generateProject\";\nexport type {\n WidgetConfig as CustomWidgetCommonConfig,\n ServiceInformation as DeploymentConfig,\n Options,\n ScaffoldTech,\n} from \"./scaffolding\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scaffolding.js","sourceRoot":"","sources":["../../src/scaffolding.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;AAC7D;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAK1C,kEAAkE;AAClE,MAAM,CAAC,MAAM,YAAY,GAAmB,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AA8B3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAU,EAAE,CAC/D,kBAAkB,CAChB,WAAW;KACR,SAAS,CAAC,KAAK,CAAC;KAChB,WAAW,EAAE;KACb,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;KAC/B,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAC/B,CAAC;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,+BAA+B,IAAI,EAAE,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Unique identifier under which is specified which port to use for injecting locally hosted custom widget to a running DevPortal instance.\n */\nexport const OVERRIDE_PORT_KEY = \"MS_APIM_CW_localhost_port\";\n/**\n * Default port for running local dev server on.\n */\nexport const OVERRIDE_DEFAULT_PORT = 3000;\n\n/** All supported technologies to scaffold a widget in. */\nexport type ScaffoldTech = \"typescript\" | \"react\" | \"vue\";\n\n/** List of all supported technologies to scaffold a widget in. */\nexport const TECHNOLOGIES: ScaffoldTech[] = [\"typescript\", \"react\", \"vue\"];\n\n/** Main data which DevPortal needs for every custom widget. */\nexport interface WidgetConfig {\n /** Name of the custom widget which is displayed in DevPortal. */\n displayName: string;\n /** Technology to use to scaffold the widget. */\n technology: ScaffoldTech;\n /** Optional URL for a custom icon, which will be displayed in DevPortal widget list. */\n iconUrl?: string;\n}\n\n/** Data needed for deployment. */\nexport interface DeploymentConfig {\n /** Management API endpoint to use (e.g. management.azure.com). */\n managementApiEndpoint: string;\n /** resourceId of your APIM service, must be in this format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<service-name> */\n resourceId: string;\n /** optional override which API version to use during deployment */\n apiVersion?: string;\n}\n\n/** Miscellaneous data for scaffolding of a custom widget which will not be stored in DevPortal. */\nexport interface Options {\n /** The URL to open after development server of the widget is started (URL of your Developer Portal). If you don't want to use this feature, set it to `false`. If you want to open just the widget page, set it to `true`. */\n openUrl?: string;\n}\n\nexport type Configs = WidgetConfig | DeploymentConfig | Options;\n\n/**\n * Converts user defined name of a custom widget to a unique ID, which is in context of Dev Portal known as \"name\".\n *\n * @param displayName - User defined name of the custom widget.\n */\nexport const displayNameToName = (displayName: string): string =>\n encodeURIComponent(\n displayName\n .normalize(\"NFD\")\n .toLowerCase()\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n );\n\n/**\n * Returns name of the folder for widget project.\n *\n * @param name - name of the widget\n */\nexport const widgetFolderName = (name: string): string => `azure-api-management-widget-${name}`;\n"]}
1
+ {"version":3,"file":"scaffolding.js","sourceRoot":"","sources":["../../src/scaffolding.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;AAC7D;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAK1C,kEAAkE;AAClE,MAAM,CAAC,MAAM,YAAY,GAAmB,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAkC3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAU,EAAE,CAC/D,kBAAkB,CAChB,WAAW;KACR,SAAS,CAAC,KAAK,CAAC;KAChB,WAAW,EAAE;KACb,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;KAC/B,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAC/B,CAAC;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,+BAA+B,IAAI,EAAE,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Unique identifier under which is specified which port to use for injecting locally hosted custom widget to a running DevPortal instance.\n */\nexport const OVERRIDE_PORT_KEY = \"MS_APIM_CW_localhost_port\";\n/**\n * Default port for running local dev server on.\n */\nexport const OVERRIDE_DEFAULT_PORT = 3000;\n\n/** All supported technologies to scaffold a widget in. */\nexport type ScaffoldTech = \"typescript\" | \"react\" | \"vue\";\n\n/** List of all supported technologies to scaffold a widget in. */\nexport const TECHNOLOGIES: ScaffoldTech[] = [\"typescript\", \"react\", \"vue\"];\n\n/** Main data which DevPortal needs for every custom widget. */\nexport interface WidgetConfig {\n /** Name of the custom widget which is displayed in DevPortal. */\n displayName: string;\n /** Technology to use to scaffold the widget. */\n technology: ScaffoldTech;\n /** Optional URL for a custom icon, which will be displayed in DevPortal widget list. */\n iconUrl?: string;\n}\n\n/** Data needed for deployment. */\nexport interface ServiceInformation {\n /** Management API endpoint to use (e.g. management.azure.com). */\n managementApiEndpoint: string;\n /** resourceId of your APIM service, must be in this format: subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ApiManagement/service/<service-name> */\n resourceId: string;\n /** optional override which API version to use during deployment */\n apiVersion?: string;\n}\n\n/** Miscellaneous data for scaffolding of a custom widget which will not be stored in DevPortal. */\nexport interface Options {\n /** The URL to open after development server of the widget is started (URL of your Developer Portal). If you don't want to use this feature, set it to `false`. If you want to open just the widget page, set it to `true`. */\n openUrl?: string;\n /** advance configuration option for the deploy function - tenant ID for InteractiveBrowserCredentialNodeOptions */\n configAdvancedTenantId?: string;\n /** advance configuration option for the deploy function - redirect URI for InteractiveBrowserCredentialNodeOptions */\n configAdvancedRedirectUri?: string;\n}\n\nexport type Configs = WidgetConfig | ServiceInformation | Options;\n\n/**\n * Converts user defined name of a custom widget to a unique ID, which is in context of Dev Portal known as \"name\".\n *\n * @param displayName - User defined name of the custom widget.\n */\nexport const displayNameToName = (displayName: string): string =>\n encodeURIComponent(\n displayName\n .normalize(\"NFD\")\n .toLowerCase()\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n );\n\n/**\n * Returns name of the folder for widget project.\n *\n * @param name - name of the widget\n */\nexport const widgetFolderName = (name: string): string => `azure-api-management-widget-${name}`;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure/api-management-custom-widgets-scaffolder",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.3",
4
4
  "author": "Microsoft Corporation",
5
5
  "license": "MIT",
6
6
  "sdk-type": "client",
@@ -16,7 +16,7 @@
16
16
  "create-apimanagement-widget": "bin/execute.js"
17
17
  },
18
18
  "engines": {
19
- "node": ">=12.0.0"
19
+ "node": ">=14.0.0"
20
20
  },
21
21
  "keywords": [
22
22
  "azure",
@@ -49,7 +49,7 @@
49
49
  "extract-api": "tsc -p . && api-extractor run --local",
50
50
  "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore --ignore-path ./.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
51
51
  "integration-test:browser": "echo skip",
52
- "integration-test:node": "dev-tool run test:node-ts-input -- --timeout 1200000 --exclude 'test/**/browser/*.spec.ts' 'test/**/*.spec.ts'",
52
+ "integration-test:node": "dev-tool run test:node-ts-input --no-test-proxy=true",
53
53
  "integration-test": "npm run integration-test:node && npm run integration-test:browser",
54
54
  "lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion] --ignore-pattern src/templates",
55
55
  "lint": "eslint package.json api-extractor.json src test --ext .ts --ignore-pattern src/templates",
@@ -63,42 +63,43 @@
63
63
  },
64
64
  "devDependencies": {
65
65
  "@azure/dev-tool": "^1.0.0",
66
- "@microsoft/api-extractor": "7.18.11",
66
+ "@microsoft/api-extractor": "^7.31.1",
67
67
  "@types/chai": "^4.1.6",
68
- "@types/mocha": "^7.0.2",
69
- "@types/node": "^12.0.0",
70
- "@types/glob": "^7.1.1",
68
+ "@types/mocha": "^10.0.0",
69
+ "@types/node": "^14.0.0",
71
70
  "@types/inquirer": "^8.2.1",
72
71
  "@types/yargs": "^17.0.10",
73
72
  "@types/yargs-parser": "^21.0.0",
74
73
  "@azure/eslint-plugin-azure-sdk": "^3.0.0",
75
74
  "chai": "^4.2.0",
76
75
  "cross-env": "^7.0.2",
77
- "eslint": "^7.15.0",
78
- "mocha": "^7.1.1",
76
+ "eslint": "^8.0.0",
77
+ "magic-string": "~0.27.0",
78
+ "mocha": "^10.0.0",
79
79
  "mocha-junit-reporter": "^2.0.0",
80
80
  "prettier": "^2.5.1",
81
81
  "nyc": "^15.0.0",
82
82
  "rimraf": "^3.0.0",
83
- "typescript": "~4.6.0",
83
+ "ts-node": "^10.0.0",
84
+ "typescript": "~5.0.0",
84
85
  "util": "^0.12.1",
85
- "dotenv": "^8.2.0",
86
+ "dotenv": "^16.0.0",
86
87
  "@azure/test-utils": "^1.0.0",
87
- "@types/mustache": "4.1.2",
88
- "sinon": "^9.0.4",
89
- "@types/sinon": "^9.0.4"
88
+ "@types/mustache": "^4.2.1",
89
+ "sinon": "^15.0.0",
90
+ "@types/sinon": "^10.0.0"
90
91
  },
91
92
  "dependencies": {
92
93
  "mustache": "^4.2.0",
93
94
  "prettier": "^2.5.1",
94
- "glob": "^7.1.2",
95
+ "glob": "^9.0.0",
95
96
  "tslib": "^2.2.0",
96
- "typescript": "~4.6.4",
97
+ "typescript": "~5.0.0",
97
98
  "chalk": "^4.1.2",
98
99
  "inquirer": "^8.2.4",
99
100
  "yargs": "^17.0.1",
100
101
  "yargs-parser": "^21.0.1",
101
- "rollup": "~2.75.5",
102
- "@rollup/plugin-node-resolve": "~13.3.0"
102
+ "rollup": "^2.66.1",
103
+ "@rollup/plugin-node-resolve": "^13.1.3"
103
104
  }
104
105
  }
@@ -42,6 +42,10 @@ export declare function generateProject(widgetConfig: CustomWidgetCommonConfig,
42
42
  export declare interface Options {
43
43
  /** The URL to open after development server of the widget is started (URL of your Developer Portal). If you don't want to use this feature, set it to `false`. If you want to open just the widget page, set it to `true`. */
44
44
  openUrl?: string;
45
+ /** advance configuration option for the deploy function - tenant ID for InteractiveBrowserCredentialNodeOptions */
46
+ configAdvancedTenantId?: string;
47
+ /** advance configuration option for the deploy function - redirect URI for InteractiveBrowserCredentialNodeOptions */
48
+ configAdvancedRedirectUri?: string;
45
49
  }
46
50
 
47
51
  /**