@botpress/cli 0.9.6 → 0.11.0
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/.turbo/turbo-build.log +8 -8
- package/dist/code-generation/integration-implementation.js +17 -17
- package/dist/code-generation/integration-implementation.js.map +2 -2
- package/dist/code-generation/integration-instance.js +18 -18
- package/dist/code-generation/integration-instance.js.map +2 -2
- package/dist/code-generation/integration-schemas/channels-module.js +6 -6
- package/dist/code-generation/integration-schemas/channels-module.js.map +2 -2
- package/dist/command-definitions.js +2 -1
- package/dist/command-definitions.js.map +2 -2
- package/dist/command-implementations/index.js +3 -1
- package/dist/command-implementations/index.js.map +2 -2
- package/dist/command-implementations/lint-command.js +59 -0
- package/dist/command-implementations/lint-command.js.map +7 -0
- package/dist/config.js +5 -1
- package/dist/config.js.map +2 -2
- package/dist/errors.js.map +2 -2
- package/dist/integration-ref.test.js +2 -3
- package/dist/integration-ref.test.js.map +2 -2
- package/dist/linter/integration-linter.js +73 -0
- package/dist/linter/integration-linter.js.map +7 -0
- package/dist/linter/integration-linter.test.js +180 -0
- package/dist/linter/integration-linter.test.js.map +7 -0
- package/dist/linter/rulesets/integration.ruleset.js +354 -0
- package/dist/linter/rulesets/integration.ruleset.js.map +7 -0
- package/dist/linter/rulesets/integration.ruleset.test.js +825 -0
- package/dist/linter/rulesets/integration.ruleset.test.js.map +7 -0
- package/dist/linter/spectral-functions.js +36 -0
- package/dist/linter/spectral-functions.js.map +7 -0
- package/dist/logger/base-logger.js.map +2 -2
- package/dist/logger/index.js.map +2 -2
- package/dist/utils/cache-utils.js.map +2 -2
- package/dist/utils/event-emitter.js +6 -6
- package/dist/utils/event-emitter.js.map +2 -2
- package/dist/utils/file-watcher.js +7 -7
- package/dist/utils/file-watcher.js.map +2 -2
- package/dist/utils/prompt-utils.js.map +2 -2
- package/dist/utils/tunnel-utils.js.map +2 -2
- package/e2e/index.ts +1 -1
- package/package.json +5 -2
- package/templates/echo-bot/package.json +1 -1
- package/templates/empty-integration/package.json +1 -1
- package/templates/hello-world/package.json +1 -1
- package/templates/webhook-message/package.json +1 -1
package/dist/errors.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/errors.ts"],
|
|
4
|
-
"sourcesContent": ["import { isApiError, ApiError, UnknownError } from '@botpress/client'\nimport axios, { AxiosError } from 'axios'\nimport { VError } from 'verror'\nimport * as consts from './consts'\n\ntype KnownApiError = Exclude<ApiError, UnknownError>\nconst isKnownApiError = (e: unknown): e is KnownApiError => isApiError(e) && !(e instanceof UnknownError)\n\nexport class BotpressCLIError extends VError {\n public static wrap(thrown: unknown, message: string): BotpressCLIError {\n const err = BotpressCLIError.map(thrown)\n return new BotpressCLIError(err, message ?? '')\n }\n\n public static map(thrown: unknown): BotpressCLIError {\n if (thrown instanceof BotpressCLIError) {\n return thrown\n }\n if (thrown instanceof UnknownError) {\n const inst = new HTTPError(500, 'An unknown error has occurred.')\n inst.debug = thrown.message\n return inst\n }\n if (isKnownApiError(thrown)) {\n return HTTPError.fromApi(thrown)\n }\n if (axios.isAxiosError(thrown)) {\n return HTTPError.fromAxios(thrown)\n }\n if (thrown instanceof Error) {\n const { message } = thrown\n return new BotpressCLIError(message)\n }\n return new BotpressCLIError(`${thrown}`)\n }\n\n private readonly _debug: string[]\n\n constructor(error: BotpressCLIError, message: string)\n constructor(message: string)\n public constructor(first: BotpressCLIError | string, second?: string) {\n if (typeof first === 'string') {\n super(first)\n this._debug = []\n return\n }\n super(first, second!)\n this._debug = [...first._debug]\n }\n\n public set debug(msg: string) {\n this._debug.push(msg)\n }\n\n public get debug(): string {\n const dbgMsgs = this._debug.filter((s) => s.length)\n if (!dbgMsgs.length) {\n return ''\n }\n return 'Error: \\n' + dbgMsgs.map((s) => ` ${s}`).join('\\n')\n }\n}\n\nexport class ExclusiveBotFeatureError extends BotpressCLIError {\n constructor() {\n const message = 'This feature is only available for bots. This project is an integration or interface.'\n super(message)\n }\n}\n\nexport class ExclusiveIntegrationFeatureError extends BotpressCLIError {\n constructor() {\n const message = 'This feature is only available for integration. This project is a bot or interface.'\n super(message)\n }\n}\n\nexport class HTTPError extends BotpressCLIError {\n constructor(public readonly status: number | undefined, message: string) {\n super(message)\n }\n\n public static fromAxios(e: AxiosError<{ message?: string }>): HTTPError {\n const message = this._axiosMsg(e)\n return new HTTPError(e.response?.status, message)\n }\n\n public static fromApi(e: KnownApiError): HTTPError {\n const { message, code } = e\n return new HTTPError(code, message)\n }\n\n private static _axiosMsg(e: AxiosError<{ message?: string }>): string {\n let message = e.message\n if (e.response?.statusText) {\n message += `\\n ${e.response?.statusText}`\n }\n if (e.response?.status && e.request?.method && e.request?.path) {\n message += `\\n (${e.response?.status}) ${e.request.method} ${e.request.path}`\n }\n if (e.response?.data?.message) {\n message += `\\n ${e.response?.data?.message}`\n }\n return message\n }\n}\n\nexport class NoBundleFoundError extends BotpressCLIError {\n constructor() {\n const message = 'No bundle found. Please run `bp bundle` first.'\n super(message)\n }\n}\n\nexport class NoBotsFoundError extends BotpressCLIError {\n constructor() {\n const message = `No Bot found in your Workspace. Please create one first at ${consts.defaultBotpressAppUrl}.`\n super(message)\n }\n}\n\nexport class NoWorkspacesFoundError extends BotpressCLIError {\n constructor() {\n const message = 'No Workspace found. Please create one first.'\n super(message)\n }\n}\n\nexport class NotLoggedInError extends BotpressCLIError {\n constructor() {\n const message = 'Not logged in. Please run `bp login` first.'\n super(message)\n }\n}\n\nexport class ParamRequiredError extends BotpressCLIError {\n constructor(param: string) {\n const message = `${param} is required.`\n super(message)\n }\n}\n\nexport class InvalidIntegrationReferenceError extends BotpressCLIError {\n constructor(ref: string) {\n const message = `Invalid integration reference \"${ref}\".`\n super(message)\n }\n}\n\nexport class InvalidInterfaceReferenceError extends BotpressCLIError {\n constructor(ref: string) {\n const message = `Invalid interface reference \"${ref}\".`\n super(message)\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmD;AACnD,mBAAkC;AAClC,oBAAuB;AACvB,aAAwB;AAGxB,MAAM,kBAAkB,CAAC,UAAmC,0BAAW,CAAC,KAAK,EAAE,aAAa;AAErF,MAAM,yBAAyB,qBAAO;AAAA,EAC3C,OAAc,KAAK,QAAiB,SAAmC;AACrE,UAAM,MAAM,iBAAiB,IAAI,MAAM;AACvC,WAAO,IAAI,iBAAiB,KAAK,WAAW,EAAE;AAAA,EAChD;AAAA,EAEA,OAAc,IAAI,QAAmC;AACnD,QAAI,kBAAkB,kBAAkB;AACtC,aAAO;AAAA,IACT;AACA,QAAI,kBAAkB,4BAAc;AAClC,YAAM,OAAO,IAAI,UAAU,KAAK,gCAAgC;AAChE,WAAK,QAAQ,OAAO;AACpB,aAAO;AAAA,IACT;AACA,QAAI,gBAAgB,MAAM,GAAG;AAC3B,aAAO,UAAU,QAAQ,MAAM;AAAA,IACjC;AACA,QAAI,aAAAA,QAAM,aAAa,MAAM,GAAG;AAC9B,aAAO,UAAU,UAAU,MAAM;AAAA,IACnC;AACA,QAAI,kBAAkB,OAAO;AAC3B,YAAM,EAAE,QAAQ,IAAI;AACpB,aAAO,IAAI,iBAAiB,OAAO;AAAA,IACrC;AACA,WAAO,IAAI,iBAAiB,GAAG,QAAQ;AAAA,EACzC;AAAA,EAEiB;AAAA,EAIV,YAAY,OAAkC,QAAiB;AACpE,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,KAAK;AACX,WAAK,SAAS,CAAC;AACf;AAAA,IACF;AACA,UAAM,OAAO,MAAO;AACpB,SAAK,SAAS,CAAC,GAAG,MAAM,MAAM;AAAA,EAChC;AAAA,EAEA,IAAW,MAAM,KAAa;AAC5B,SAAK,OAAO,KAAK,GAAG;AAAA,EACtB;AAAA,EAEA,IAAW,QAAgB;AACzB,UAAM,UAAU,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM;AAClD,QAAI,CAAC,QAAQ,QAAQ;AACnB,aAAO;AAAA,IACT;AACA,WAAO,cAAc,QAAQ,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,KAAK,IAAI;AAAA,EAC7D;AACF;AAEO,MAAM,iCAAiC,iBAAiB;AAAA,
|
|
4
|
+
"sourcesContent": ["import { isApiError, ApiError, UnknownError } from '@botpress/client'\nimport axios, { AxiosError } from 'axios'\nimport { VError } from 'verror'\nimport * as consts from './consts'\n\ntype KnownApiError = Exclude<ApiError, UnknownError>\nconst isKnownApiError = (e: unknown): e is KnownApiError => isApiError(e) && !(e instanceof UnknownError)\n\nexport class BotpressCLIError extends VError {\n public static wrap(thrown: unknown, message: string): BotpressCLIError {\n const err = BotpressCLIError.map(thrown)\n return new BotpressCLIError(err, message ?? '')\n }\n\n public static map(thrown: unknown): BotpressCLIError {\n if (thrown instanceof BotpressCLIError) {\n return thrown\n }\n if (thrown instanceof UnknownError) {\n const inst = new HTTPError(500, 'An unknown error has occurred.')\n inst.debug = thrown.message\n return inst\n }\n if (isKnownApiError(thrown)) {\n return HTTPError.fromApi(thrown)\n }\n if (axios.isAxiosError(thrown)) {\n return HTTPError.fromAxios(thrown)\n }\n if (thrown instanceof Error) {\n const { message } = thrown\n return new BotpressCLIError(message)\n }\n return new BotpressCLIError(`${thrown}`)\n }\n\n private readonly _debug: string[]\n\n public constructor(error: BotpressCLIError, message: string)\n public constructor(message: string)\n public constructor(first: BotpressCLIError | string, second?: string) {\n if (typeof first === 'string') {\n super(first)\n this._debug = []\n return\n }\n super(first, second!)\n this._debug = [...first._debug]\n }\n\n public set debug(msg: string) {\n this._debug.push(msg)\n }\n\n public get debug(): string {\n const dbgMsgs = this._debug.filter((s) => s.length)\n if (!dbgMsgs.length) {\n return ''\n }\n return 'Error: \\n' + dbgMsgs.map((s) => ` ${s}`).join('\\n')\n }\n}\n\nexport class ExclusiveBotFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for bots. This project is an integration or interface.'\n super(message)\n }\n}\n\nexport class ExclusiveIntegrationFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for integration. This project is a bot or interface.'\n super(message)\n }\n}\n\nexport class HTTPError extends BotpressCLIError {\n public constructor(public readonly status: number | undefined, message: string) {\n super(message)\n }\n\n public static fromAxios(e: AxiosError<{ message?: string }>): HTTPError {\n const message = this._axiosMsg(e)\n return new HTTPError(e.response?.status, message)\n }\n\n public static fromApi(e: KnownApiError): HTTPError {\n const { message, code } = e\n return new HTTPError(code, message)\n }\n\n private static _axiosMsg(e: AxiosError<{ message?: string }>): string {\n let message = e.message\n if (e.response?.statusText) {\n message += `\\n ${e.response?.statusText}`\n }\n if (e.response?.status && e.request?.method && e.request?.path) {\n message += `\\n (${e.response?.status}) ${e.request.method} ${e.request.path}`\n }\n if (e.response?.data?.message) {\n message += `\\n ${e.response?.data?.message}`\n }\n return message\n }\n}\n\nexport class NoBundleFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No bundle found. Please run `bp bundle` first.'\n super(message)\n }\n}\n\nexport class NoBotsFoundError extends BotpressCLIError {\n public constructor() {\n const message = `No Bot found in your Workspace. Please create one first at ${consts.defaultBotpressAppUrl}.`\n super(message)\n }\n}\n\nexport class NoWorkspacesFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No Workspace found. Please create one first.'\n super(message)\n }\n}\n\nexport class NotLoggedInError extends BotpressCLIError {\n public constructor() {\n const message = 'Not logged in. Please run `bp login` first.'\n super(message)\n }\n}\n\nexport class ParamRequiredError extends BotpressCLIError {\n public constructor(param: string) {\n const message = `${param} is required.`\n super(message)\n }\n}\n\nexport class InvalidIntegrationReferenceError extends BotpressCLIError {\n public constructor(ref: string) {\n const message = `Invalid integration reference \"${ref}\".`\n super(message)\n }\n}\n\nexport class InvalidInterfaceReferenceError extends BotpressCLIError {\n public constructor(ref: string) {\n const message = `Invalid interface reference \"${ref}\".`\n super(message)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["axios"]
|
|
7
7
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var import_node_test = require("node:test");
|
|
3
2
|
var import_vitest = require("vitest");
|
|
4
3
|
var import_integration_ref = require("./integration-ref");
|
|
5
4
|
const path = "/my/path";
|
|
6
5
|
const prefixedUlid = "intver_01HF58RDKE3M7K5RJ5XZ7GF6HE";
|
|
7
6
|
const uuid = "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
|
|
8
7
|
const name = "myintegration";
|
|
9
|
-
(0,
|
|
8
|
+
(0, import_vitest.describe)("parseIntegrationRef", () => {
|
|
10
9
|
(0, import_vitest.test)("parse empty string should return undefined", () => {
|
|
11
10
|
const ref = "";
|
|
12
11
|
const result = (0, import_integration_ref.parseIntegrationRef)(ref);
|
|
@@ -62,7 +61,7 @@ const name = "myintegration";
|
|
|
62
61
|
(0, import_vitest.expect)(result).toEqual(expected);
|
|
63
62
|
});
|
|
64
63
|
});
|
|
65
|
-
(0,
|
|
64
|
+
(0, import_vitest.describe)("formatIntegrationRef", () => {
|
|
66
65
|
(0, import_vitest.test)("format with a path should return path", () => {
|
|
67
66
|
const ref = { type: "path", path };
|
|
68
67
|
const result = (0, import_integration_ref.formatIntegrationRef)(ref);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/integration-ref.test.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": ";AAAA,
|
|
4
|
+
"sourcesContent": ["import { test, expect, describe } from 'vitest'\nimport { formatIntegrationRef, IntegrationRef, parseIntegrationRef } from './integration-ref'\n\nconst path = '/my/path'\nconst prefixedUlid = 'intver_01HF58RDKE3M7K5RJ5XZ7GF6HE'\nconst uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'\nconst name = 'myintegration'\n\ndescribe('parseIntegrationRef', () => {\n test('parse empty string should return undefined', () => {\n // arrange\n const ref = ''\n // act\n const result = parseIntegrationRef(ref)\n // assert\n expect(result).toBeUndefined()\n })\n\n test('parse with invalid version should return undefined', () => {\n // arrange\n const ref0 = `${name}@lol`\n const ref1 = `${name}@1`\n const ref2 = `${name}@1.0`\n // act\n const result0 = parseIntegrationRef(ref0)\n const result1 = parseIntegrationRef(ref1)\n const result2 = parseIntegrationRef(ref2)\n // assert\n expect(result0).toBeUndefined()\n expect(result1).toBeUndefined()\n expect(result2).toBeUndefined()\n })\n\n test('parse with an absolute path should return path', () => {\n // arrange\n const ref = path\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'path', path: ref }\n expect(result).toEqual(expected)\n })\n\n test('parse with a prefixed ULID sets `id` type', () => {\n // arrange\n const ref = prefixedUlid\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'id', id: ref }\n expect(result).toEqual(expected)\n })\n\n test('parse with a legacy UUID sets `id` type', () => {\n // arrange\n const ref = uuid\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'id', id: ref }\n expect(result).toEqual(expected)\n })\n\n test('parse with a name and version should return name and version', () => {\n // arrange\n const version = '1.0.0'\n const ref = `${name}@${version}`\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'name', name, version }\n expect(result).toEqual(expected)\n })\n\n test('parse with a name and latest should return name and latest', () => {\n // arrange\n const version = 'latest'\n const ref = `${name}@${version}`\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'name', name, version }\n expect(result).toEqual(expected)\n })\n\n test('parse with only a name should return name and latest', () => {\n // arrange\n const ref = name\n // act\n const result = parseIntegrationRef(ref)\n // assert\n const expected: IntegrationRef = { type: 'name', name, version: 'latest' }\n expect(result).toEqual(expected)\n })\n})\n\ndescribe('formatIntegrationRef', () => {\n test('format with a path should return path', () => {\n // arrange\n const ref: IntegrationRef = { type: 'path', path }\n // act\n const result = formatIntegrationRef(ref)\n // assert\n expect(result).toEqual(ref.path)\n })\n\n test('format with a prefixed ULID uses `id` type', () => {\n // arrange\n const ref: IntegrationRef = { type: 'id', id: prefixedUlid }\n // act\n const result = formatIntegrationRef(ref)\n // assert\n expect(result).toEqual(ref.id)\n })\n\n test('format with a legacy UUID uses `id` type', () => {\n // arrange\n const ref: IntegrationRef = { type: 'id', id: uuid }\n // act\n const result = formatIntegrationRef(ref)\n // assert\n expect(result).toEqual(ref.id)\n })\n\n test('format with a name and version should return name and version', () => {\n // arrange\n const version = '1.0.0'\n const ref: IntegrationRef = { type: 'name', name, version }\n // act\n const result = formatIntegrationRef(ref)\n // assert\n expect(result).toEqual(`${name}@${version}`)\n })\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var integration_linter_exports = {};
|
|
20
|
+
__export(integration_linter_exports, {
|
|
21
|
+
IntegrationLinter: () => IntegrationLinter
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(integration_linter_exports);
|
|
24
|
+
var import_spectral_core = require("@stoplight/spectral-core");
|
|
25
|
+
var import_spectral_parsers = require("@stoplight/spectral-parsers");
|
|
26
|
+
var import_integration = require("./rulesets/integration.ruleset");
|
|
27
|
+
class IntegrationLinter {
|
|
28
|
+
_spectral;
|
|
29
|
+
_spectralDocument;
|
|
30
|
+
_results = [];
|
|
31
|
+
constructor(definition) {
|
|
32
|
+
const json = JSON.stringify(definition).replaceAll('"$ref":', '"_$ref":');
|
|
33
|
+
this._spectralDocument = new import_spectral_core.Document(json, import_spectral_parsers.Json);
|
|
34
|
+
this._spectral = new import_spectral_core.Spectral();
|
|
35
|
+
this._spectral.setRuleset(import_integration.INTEGRATION_RULESET);
|
|
36
|
+
}
|
|
37
|
+
async lint() {
|
|
38
|
+
this._results = await this._spectral.run(this._spectralDocument);
|
|
39
|
+
}
|
|
40
|
+
logResults(logger) {
|
|
41
|
+
for (const result of this.getSortedResults()) {
|
|
42
|
+
const message = `${result.path}: ${result.message}`;
|
|
43
|
+
this._logResultMessage(logger, message, result.severity);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
getSortedResults() {
|
|
47
|
+
return this._getResults().sort((a, b) => a.path > b.path ? 1 : a.path < b.path ? -1 : 0);
|
|
48
|
+
}
|
|
49
|
+
_getResults() {
|
|
50
|
+
return this._results.map((result) => ({
|
|
51
|
+
message: result.message,
|
|
52
|
+
path: this._simplifyPath(result.path),
|
|
53
|
+
severity: result.severity
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
_simplifyPath(path) {
|
|
57
|
+
return path.join(".").replaceAll(".properties.", ".").replaceAll(".x-zui", "");
|
|
58
|
+
}
|
|
59
|
+
_logResultMessage(logger, message, severity) {
|
|
60
|
+
const logLevelMapping = {
|
|
61
|
+
0: logger.error,
|
|
62
|
+
1: logger.warn,
|
|
63
|
+
2: logger.log,
|
|
64
|
+
3: logger.debug
|
|
65
|
+
};
|
|
66
|
+
logLevelMapping[severity].call(logger, message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
+
0 && (module.exports = {
|
|
71
|
+
IntegrationLinter
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=integration-linter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/linter/integration-linter.ts"],
|
|
4
|
+
"sourcesContent": ["import { Spectral, Document, ISpectralDiagnostic } from '@stoplight/spectral-core'\nimport { Json as JsonParser, JsonParserResult } from '@stoplight/spectral-parsers'\nimport { CreateIntegrationBody } from '../api/integration-body'\nimport { Logger } from '../logger'\nimport { INTEGRATION_RULESET } from './rulesets/integration.ruleset'\n\ntype ProblemSeverity = 0 | 1 | 2 | 3\n\nexport class IntegrationLinter {\n private readonly _spectral: Spectral\n private readonly _spectralDocument: Document<unknown, JsonParserResult<unknown>>\n private _results: ISpectralDiagnostic[] = []\n\n public constructor(definition: CreateIntegrationBody) {\n const json = JSON.stringify(definition).replaceAll('\"$ref\":', '\"_$ref\":')\n this._spectralDocument = new Document(json, JsonParser)\n this._spectral = new Spectral()\n\n this._spectral.setRuleset(INTEGRATION_RULESET)\n }\n\n public async lint(): Promise<void> {\n this._results = await this._spectral.run(this._spectralDocument)\n }\n\n public logResults(logger: Logger) {\n for (const result of this.getSortedResults()) {\n const message = `${result.path}: ${result.message}`\n\n this._logResultMessage(logger, message, result.severity)\n }\n }\n\n public getSortedResults() {\n return this._getResults().sort((a, b) => (a.path > b.path ? 1 : a.path < b.path ? -1 : 0))\n }\n\n private _getResults() {\n return this._results.map((result) => ({\n message: result.message,\n path: this._simplifyPath(result.path),\n severity: result.severity as ProblemSeverity,\n }))\n }\n\n private _simplifyPath(path: (string | number)[]) {\n return path.join('.').replaceAll('.properties.', '.').replaceAll('.x-zui', '')\n }\n\n private _logResultMessage(logger: Logger, message: string, severity: ProblemSeverity) {\n const logLevelMapping = {\n 0: logger.error,\n 1: logger.warn,\n 2: logger.log,\n 3: logger.debug,\n } as const\n\n logLevelMapping[severity].call(logger, message)\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAwD;AACxD,8BAAqD;AAGrD,yBAAoC;AAI7B,MAAM,kBAAkB;AAAA,EACZ;AAAA,EACA;AAAA,EACT,WAAkC,CAAC;AAAA,EAEpC,YAAY,YAAmC;AACpD,UAAM,OAAO,KAAK,UAAU,UAAU,EAAE,WAAW,WAAW,UAAU;AACxE,SAAK,oBAAoB,IAAI,8BAAS,MAAM,wBAAAA,IAAU;AACtD,SAAK,YAAY,IAAI,8BAAS;AAE9B,SAAK,UAAU,WAAW,sCAAmB;AAAA,EAC/C;AAAA,EAEA,MAAa,OAAsB;AACjC,SAAK,WAAW,MAAM,KAAK,UAAU,IAAI,KAAK,iBAAiB;AAAA,EACjE;AAAA,EAEO,WAAW,QAAgB;AAChC,eAAW,UAAU,KAAK,iBAAiB,GAAG;AAC5C,YAAM,UAAU,GAAG,OAAO,SAAS,OAAO;AAE1C,WAAK,kBAAkB,QAAQ,SAAS,OAAO,QAAQ;AAAA,IACzD;AAAA,EACF;AAAA,EAEO,mBAAmB;AACxB,WAAO,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAO,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,CAAE;AAAA,EAC3F;AAAA,EAEQ,cAAc;AACpB,WAAO,KAAK,SAAS,IAAI,CAAC,YAAY;AAAA,MACpC,SAAS,OAAO;AAAA,MAChB,MAAM,KAAK,cAAc,OAAO,IAAI;AAAA,MACpC,UAAU,OAAO;AAAA,IACnB,EAAE;AAAA,EACJ;AAAA,EAEQ,cAAc,MAA2B;AAC/C,WAAO,KAAK,KAAK,GAAG,EAAE,WAAW,gBAAgB,GAAG,EAAE,WAAW,UAAU,EAAE;AAAA,EAC/E;AAAA,EAEQ,kBAAkB,QAAgB,SAAiB,UAA2B;AACpF,UAAM,kBAAkB;AAAA,MACtB,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,IACZ;AAEA,oBAAgB,UAAU,KAAK,QAAQ,OAAO;AAAA,EAChD;AACF;",
|
|
6
|
+
"names": ["JsonParser"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var import_vitest = require("vitest");
|
|
3
|
+
var import_integration_body = require("../api/integration-body");
|
|
4
|
+
var import_integration_linter = require("./integration-linter");
|
|
5
|
+
var import_sdk = require("@botpress/sdk");
|
|
6
|
+
const EMPTY_STRING = "";
|
|
7
|
+
const TRUTHY_STRING = "truthy";
|
|
8
|
+
const ACTION_NAME = "actionName";
|
|
9
|
+
const EVENT_NAME = "eventName";
|
|
10
|
+
const CONFIG_NAME = "configName";
|
|
11
|
+
const PARAM_NAME = "paramName";
|
|
12
|
+
const TAG_NAME = "tagName";
|
|
13
|
+
const CHANNEL_NAME = "channelName";
|
|
14
|
+
const STATE_NAME = "stateName";
|
|
15
|
+
const MESSAGE_TYPE = "text";
|
|
16
|
+
const VALID_INTEGRATION = {
|
|
17
|
+
name: TRUTHY_STRING,
|
|
18
|
+
title: TRUTHY_STRING,
|
|
19
|
+
description: TRUTHY_STRING,
|
|
20
|
+
version: TRUTHY_STRING,
|
|
21
|
+
readme: TRUTHY_STRING,
|
|
22
|
+
icon: TRUTHY_STRING,
|
|
23
|
+
actions: {
|
|
24
|
+
[ACTION_NAME]: {
|
|
25
|
+
title: TRUTHY_STRING,
|
|
26
|
+
description: TRUTHY_STRING,
|
|
27
|
+
input: {
|
|
28
|
+
schema: import_sdk.z.object({
|
|
29
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
30
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
31
|
+
},
|
|
32
|
+
output: {
|
|
33
|
+
schema: import_sdk.z.object({
|
|
34
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
35
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
events: {
|
|
40
|
+
[EVENT_NAME]: {
|
|
41
|
+
title: TRUTHY_STRING,
|
|
42
|
+
description: TRUTHY_STRING,
|
|
43
|
+
schema: import_sdk.z.object({
|
|
44
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
45
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
configuration: {
|
|
49
|
+
schema: import_sdk.z.object({
|
|
50
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
51
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
52
|
+
},
|
|
53
|
+
configurations: {
|
|
54
|
+
[CONFIG_NAME]: {
|
|
55
|
+
title: TRUTHY_STRING,
|
|
56
|
+
description: TRUTHY_STRING,
|
|
57
|
+
schema: import_sdk.z.object({
|
|
58
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
59
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
user: {
|
|
63
|
+
tags: {
|
|
64
|
+
[TAG_NAME]: {
|
|
65
|
+
title: TRUTHY_STRING,
|
|
66
|
+
description: TRUTHY_STRING
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
channels: {
|
|
71
|
+
[CHANNEL_NAME]: {
|
|
72
|
+
title: TRUTHY_STRING,
|
|
73
|
+
description: TRUTHY_STRING,
|
|
74
|
+
messages: {
|
|
75
|
+
[MESSAGE_TYPE]: {
|
|
76
|
+
schema: import_sdk.z.object({
|
|
77
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
78
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
message: {
|
|
82
|
+
tags: {
|
|
83
|
+
[TAG_NAME]: {
|
|
84
|
+
title: TRUTHY_STRING,
|
|
85
|
+
description: TRUTHY_STRING
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
conversation: {
|
|
90
|
+
tags: {
|
|
91
|
+
[TAG_NAME]: {
|
|
92
|
+
title: TRUTHY_STRING,
|
|
93
|
+
description: TRUTHY_STRING
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
states: {
|
|
100
|
+
[STATE_NAME]: {
|
|
101
|
+
type: "integration",
|
|
102
|
+
schema: import_sdk.z.object({
|
|
103
|
+
[PARAM_NAME]: import_sdk.z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
104
|
+
}).title(TRUTHY_STRING).describe(TRUTHY_STRING)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const mockLogger = {
|
|
109
|
+
log: import_vitest.vi.fn((message) => void 0),
|
|
110
|
+
warn: import_vitest.vi.fn((message) => void 0),
|
|
111
|
+
error: import_vitest.vi.fn((message) => void 0),
|
|
112
|
+
debug: import_vitest.vi.fn((message) => void 0)
|
|
113
|
+
};
|
|
114
|
+
const lintDefinition = async (definition) => {
|
|
115
|
+
const integrationDefinition = new import_sdk.IntegrationDefinition(definition);
|
|
116
|
+
const linter = new import_integration_linter.IntegrationLinter((0, import_integration_body.prepareCreateIntegrationBody)(integrationDefinition));
|
|
117
|
+
await linter.lint();
|
|
118
|
+
return linter;
|
|
119
|
+
};
|
|
120
|
+
const lintDefinitionAndReturnResults = async (definition) => {
|
|
121
|
+
const linter = await lintDefinition(definition);
|
|
122
|
+
return linter.getSortedResults();
|
|
123
|
+
};
|
|
124
|
+
const lintDefinitionAndLogResults = async (definition) => {
|
|
125
|
+
const linter = await lintDefinition(definition);
|
|
126
|
+
linter.logResults(mockLogger);
|
|
127
|
+
};
|
|
128
|
+
import_vitest.describe.concurrent("Integration Linter", () => {
|
|
129
|
+
(0, import_vitest.test)("should lint a valid definition without giving errors", async () => {
|
|
130
|
+
const definition = VALID_INTEGRATION;
|
|
131
|
+
const results = await lintDefinitionAndReturnResults(definition);
|
|
132
|
+
(0, import_vitest.expect)(results).toEqual([]);
|
|
133
|
+
});
|
|
134
|
+
(0, import_vitest.test)("should report an error when missing required fields", async () => {
|
|
135
|
+
const definition = {
|
|
136
|
+
...VALID_INTEGRATION,
|
|
137
|
+
title: EMPTY_STRING
|
|
138
|
+
};
|
|
139
|
+
const results = await lintDefinitionAndReturnResults(definition);
|
|
140
|
+
(0, import_vitest.expect)(results[0]?.message).toContain("title");
|
|
141
|
+
});
|
|
142
|
+
(0, import_vitest.test)("should report an error when missing a title in an action input schema", async () => {
|
|
143
|
+
const definition = {
|
|
144
|
+
...VALID_INTEGRATION,
|
|
145
|
+
actions: {
|
|
146
|
+
[ACTION_NAME]: {
|
|
147
|
+
...VALID_INTEGRATION.actions[ACTION_NAME],
|
|
148
|
+
input: {
|
|
149
|
+
schema: import_sdk.z.object({
|
|
150
|
+
[PARAM_NAME]: import_sdk.z.string().describe(TRUTHY_STRING)
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const results = await lintDefinitionAndReturnResults(definition);
|
|
157
|
+
(0, import_vitest.expect)(results[0]?.message).toContain("title");
|
|
158
|
+
});
|
|
159
|
+
(0, import_vitest.test)("should log as an error when severity is 0", async () => {
|
|
160
|
+
const definition = {
|
|
161
|
+
...VALID_INTEGRATION,
|
|
162
|
+
title: EMPTY_STRING
|
|
163
|
+
};
|
|
164
|
+
await lintDefinitionAndLogResults(definition);
|
|
165
|
+
(0, import_vitest.expect)(mockLogger.error).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
(0, import_vitest.test)("should log as a warning when severity is 1", async () => {
|
|
168
|
+
const definition = {
|
|
169
|
+
...VALID_INTEGRATION,
|
|
170
|
+
user: {
|
|
171
|
+
tags: {
|
|
172
|
+
[TAG_NAME]: {}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
await lintDefinitionAndLogResults(definition);
|
|
177
|
+
(0, import_vitest.expect)(mockLogger.warn).toHaveBeenCalled();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=integration-linter.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/linter/integration-linter.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { test, expect, describe, vi } from 'vitest'\nimport { prepareCreateIntegrationBody } from '../api/integration-body'\nimport { IntegrationLinter } from './integration-linter'\nimport { IntegrationDefinition, IntegrationDefinitionProps, z } from '@botpress/sdk'\nimport { Logger } from 'src/logger'\n\nconst EMPTY_STRING = ''\nconst TRUTHY_STRING = 'truthy'\nconst ACTION_NAME = 'actionName'\nconst EVENT_NAME = 'eventName'\nconst CONFIG_NAME = 'configName'\nconst PARAM_NAME = 'paramName'\nconst TAG_NAME = 'tagName'\nconst CHANNEL_NAME = 'channelName'\nconst STATE_NAME = 'stateName'\nconst MESSAGE_TYPE = 'text'\n\nconst VALID_INTEGRATION = {\n name: TRUTHY_STRING,\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n version: TRUTHY_STRING,\n readme: TRUTHY_STRING,\n icon: TRUTHY_STRING,\n actions: {\n [ACTION_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n input: {\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n output: {\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n },\n },\n events: {\n [EVENT_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n },\n configuration: {\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n configurations: {\n [CONFIG_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n },\n user: {\n tags: {\n [TAG_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n },\n },\n },\n channels: {\n [CHANNEL_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n messages: {\n [MESSAGE_TYPE]: {\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n },\n message: {\n tags: {\n [TAG_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n },\n },\n },\n conversation: {\n tags: {\n [TAG_NAME]: {\n title: TRUTHY_STRING,\n description: TRUTHY_STRING,\n },\n },\n },\n },\n },\n states: {\n [STATE_NAME]: {\n type: 'integration',\n schema: z\n .object({\n [PARAM_NAME]: z.string().title(TRUTHY_STRING).describe(TRUTHY_STRING),\n })\n .title(TRUTHY_STRING)\n .describe(TRUTHY_STRING),\n },\n },\n} as const satisfies IntegrationDefinitionProps\n\nconst mockLogger = {\n log: vi.fn((message) => void message),\n warn: vi.fn((message) => void message),\n error: vi.fn((message) => void message),\n debug: vi.fn((message) => void message),\n}\n\nconst lintDefinition = async (definition: IntegrationDefinitionProps) => {\n const integrationDefinition = new IntegrationDefinition(definition)\n const linter = new IntegrationLinter(prepareCreateIntegrationBody(integrationDefinition))\n await linter.lint()\n return linter\n}\n\nconst lintDefinitionAndReturnResults = async (definition: IntegrationDefinitionProps) => {\n const linter = await lintDefinition(definition)\n return linter.getSortedResults()\n}\n\nconst lintDefinitionAndLogResults = async (definition: IntegrationDefinitionProps) => {\n const linter = await lintDefinition(definition)\n linter.logResults(mockLogger as any)\n}\n\ndescribe.concurrent('Integration Linter', () => {\n test('should lint a valid definition without giving errors', async () => {\n // arrange\n const definition = VALID_INTEGRATION\n\n // act\n const results = await lintDefinitionAndReturnResults(definition)\n\n expect(results).toEqual([])\n })\n\n test('should report an error when missing required fields', async () => {\n // arrange\n const definition = {\n ...VALID_INTEGRATION,\n title: EMPTY_STRING,\n } as const\n\n // act\n const results = await lintDefinitionAndReturnResults(definition)\n\n // assert\n expect(results[0]?.message).toContain('title')\n })\n\n test('should report an error when missing a title in an action input schema', async () => {\n // arrange\n const definition = {\n ...VALID_INTEGRATION,\n actions: {\n [ACTION_NAME]: {\n ...VALID_INTEGRATION.actions[ACTION_NAME],\n input: {\n schema: z.object({\n [PARAM_NAME]: z.string().describe(TRUTHY_STRING),\n }),\n },\n },\n },\n } as const\n\n // act\n const results = await lintDefinitionAndReturnResults(definition)\n\n // assert\n expect(results[0]?.message).toContain('title')\n })\n\n test('should log as an error when severity is 0', async () => {\n // arrange\n const definition = {\n ...VALID_INTEGRATION,\n title: EMPTY_STRING,\n } as const\n\n // act\n await lintDefinitionAndLogResults(definition)\n\n // assert\n expect(mockLogger.error).toHaveBeenCalled()\n })\n\n test('should log as a warning when severity is 1', async () => {\n // arrange\n const definition = {\n ...VALID_INTEGRATION,\n user: {\n tags: {\n [TAG_NAME]: {},\n },\n },\n } as const\n\n // act\n await lintDefinitionAndLogResults(definition)\n\n // assert\n expect(mockLogger.warn).toHaveBeenCalled()\n })\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|