thymian 0.0.1 → 0.1.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/README.md +19 -1
- package/bin/run.js +26 -0
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +28 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/config/show.d.ts +9 -0
- package/dist/commands/config/show.d.ts.map +1 -0
- package/dist/commands/config/show.js +35 -0
- package/dist/commands/config/show.js.map +1 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +95 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/generate/config.d.ts +15 -0
- package/dist/commands/generate/config.d.ts.map +1 -0
- package/dist/commands/generate/config.js +176 -0
- package/dist/commands/generate/config.js.map +1 -0
- package/dist/commands/lint.d.ts +7 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +24 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/plugins/list.d.ts +6 -0
- package/dist/commands/plugins/list.d.ts.map +1 -0
- package/dist/commands/plugins/list.js +14 -0
- package/dist/commands/plugins/list.js.map +1 -0
- package/dist/commands/schema.d.ts +5 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +30 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/serve.d.ts +8 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +31 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/test.d.ts +10 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +33 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/create-email-issue-for-error.d.ts +3 -0
- package/dist/create-email-issue-for-error.d.ts.map +1 -0
- package/dist/create-email-issue-for-error.js +31 -0
- package/dist/create-email-issue-for-error.js.map +1 -0
- package/dist/create-github-issue-url-for-error.d.ts +3 -0
- package/dist/create-github-issue-url-for-error.d.ts.map +1 -0
- package/dist/create-github-issue-url-for-error.js +45 -0
- package/dist/create-github-issue-url-for-error.js.map +1 -0
- package/dist/hooks/feedback.d.ts +4 -0
- package/dist/hooks/feedback.d.ts.map +1 -0
- package/dist/hooks/feedback.js +8 -0
- package/dist/hooks/feedback.js.map +1 -0
- package/package.json +62 -8
package/README.md
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
# @thymian/cli
|
|
2
|
+
|
|
3
|
+
Main CLI entry point for Thymian - a lightweight, language-agnostic library that helps you build robust APIs by adding resilience testing and HTTP conformance validation to your development workflow.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @thymian/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx thymian run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Documentation
|
|
18
|
+
|
|
19
|
+
For comprehensive documentation, guides, and API reference, visit [Thymian Documentation](https://thymian.dev/).
|
package/bin/run.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { getPluginNames, oclif } from '@thymian/common-cli';
|
|
6
|
+
|
|
7
|
+
const dirname = import.meta.dirname;
|
|
8
|
+
|
|
9
|
+
const thymianPath = import.meta.url.includes('node_modules')
|
|
10
|
+
? path.join(dirname, '..')
|
|
11
|
+
: path.join(dirname, 'node_modules', '@thymian', 'cli');
|
|
12
|
+
|
|
13
|
+
const pluginsPath = import.meta.url.includes('node_modules')
|
|
14
|
+
? thymianPath
|
|
15
|
+
: path.join(dirname, '..');
|
|
16
|
+
|
|
17
|
+
await oclif.execute({
|
|
18
|
+
dir: thymianPath,
|
|
19
|
+
loadOptions: {
|
|
20
|
+
pluginAdditions: {
|
|
21
|
+
core: await getPluginNames(),
|
|
22
|
+
path: pluginsPath,
|
|
23
|
+
},
|
|
24
|
+
root: thymianPath,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class Analyze extends BaseCliRunCommand<typeof Analyze> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static requiresSpecifications: boolean;
|
|
6
|
+
static requiresTraffic: boolean;
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=analyze.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,iBAAiB,CAAC,OAAO,OAAO,CAAC;IACpE,OAAgB,WAAW,SACuD;IAElF,OAAgB,QAAQ,WAItB;IAEF,OAAgB,sBAAsB,UAAS;IAC/C,OAAgB,eAAe,UAAQ;IAExB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0BpC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
|
|
2
|
+
export default class Analyze extends BaseCliRunCommand {
|
|
3
|
+
static description = 'Analyze recorded API traffic against specifications and configured rule sets.';
|
|
4
|
+
static examples = [
|
|
5
|
+
'<%= config.bin %> <%= command.id %>',
|
|
6
|
+
'<%= config.bin %> <%= command.id %> --traffic har:./traffic.har',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml --traffic har:./traffic.har',
|
|
8
|
+
];
|
|
9
|
+
static requiresSpecifications = false;
|
|
10
|
+
static requiresTraffic = true;
|
|
11
|
+
async run() {
|
|
12
|
+
const specifications = this.thymianConfig.specifications ?? [];
|
|
13
|
+
const traffic = this.thymianConfig.traffic ?? [];
|
|
14
|
+
const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
|
|
15
|
+
const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
|
|
16
|
+
const outcome = await this.thymian.run(async () => {
|
|
17
|
+
return await this.thymian.analyze({
|
|
18
|
+
specification: specifications.length > 0 ? specifications : undefined,
|
|
19
|
+
traffic,
|
|
20
|
+
rules: ruleSets,
|
|
21
|
+
rulesConfig: this.thymianConfig.rules,
|
|
22
|
+
ruleFilter: createSeverityRuleFilter(ruleSeverity),
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
handleWorkflowOutcome(this, outcome);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,iBAAiC;IACpE,MAAM,CAAU,WAAW,GACzB,+EAA+E,CAAC;IAElF,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,iEAAiE;QACjE,+FAA+F;KAChG,CAAC;IAEF,MAAM,CAAU,sBAAsB,GAAG,KAAK,CAAC;IAC/C,MAAM,CAAU,eAAe,GAAG,IAAI,CAAC;IAE9B,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,IAAI,EAAE,CAAC;QAEjD,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gBAChC,aAAa,EAAE,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;gBACrE,OAAO;gBACP,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;aACnD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class ShowConfig extends BaseCliRunCommand<typeof ShowConfig> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
yaml: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=show.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/config/show.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAiB,CAAC,OAAO,UAAU,CAAC;IAC1E,OAAgB,WAAW,SAA6C;IAExE,OAAgB,KAAK;;MAMnB;IACW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsBlC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
import { Flags, ux } from '@thymian/common-cli/oclif';
|
|
3
|
+
import { stringify } from '@thymian/common-cli/yaml';
|
|
4
|
+
export default class ShowConfig extends BaseCliRunCommand {
|
|
5
|
+
static description = 'Show the current Thymian configuration.';
|
|
6
|
+
static flags = {
|
|
7
|
+
yaml: Flags.boolean({
|
|
8
|
+
default: false,
|
|
9
|
+
allowNo: true,
|
|
10
|
+
description: 'Output configuration in YAML format.',
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
if (this.flags.yaml) {
|
|
15
|
+
this.log(stringify(this.thymianConfig));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.log(ux.colorizeJson(this.thymianConfig, {
|
|
19
|
+
pretty: true,
|
|
20
|
+
theme: {
|
|
21
|
+
brace: '#00FFFF',
|
|
22
|
+
bracket: 'rgb(0, 255, 255)',
|
|
23
|
+
colon: 'dim',
|
|
24
|
+
comma: 'yellow',
|
|
25
|
+
key: 'bold',
|
|
26
|
+
string: 'green',
|
|
27
|
+
number: 'blue',
|
|
28
|
+
boolean: 'cyan',
|
|
29
|
+
null: 'redBright',
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/config/show.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAoC;IAC1E,MAAM,CAAU,WAAW,GAAG,yCAAyC,CAAC;IAExE,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,sCAAsC;SACpD,CAAC;KACH,CAAC;IACK,KAAK,CAAC,GAAG;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CACN,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE;gBAClC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE;oBACL,KAAK,EAAE,SAAS;oBAChB,OAAO,EAAE,kBAAkB;oBAC3B,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,QAAQ;oBACf,GAAG,EAAE,MAAM;oBACX,MAAM,EAAE,OAAO;oBACf,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM;oBACf,IAAI,EAAE,WAAW;iBAClB;aACF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ThymianBaseCommand } from '@thymian/common-cli';
|
|
2
|
+
export declare class Feedback extends ThymianBaseCommand<typeof Feedback> {
|
|
3
|
+
protected static CONTACT: string;
|
|
4
|
+
shouldSuppressFeedback(): boolean;
|
|
5
|
+
run(): Promise<void>;
|
|
6
|
+
private reportError;
|
|
7
|
+
private provideFeedback;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/commands/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAM7B,qBAAa,QAAS,SAAQ,kBAAkB,CAAC,OAAO,QAAQ,CAAC;IAC/D,SAAS,CAAC,MAAM,CAAC,OAAO,SAAkC;IAEjD,sBAAsB,IAAI,OAAO;IAI3B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA4BrB,WAAW;YAqCX,eAAe;CAqC9B"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { oclif, prompts, ThymianBaseCommand, } from '@thymian/common-cli';
|
|
2
|
+
import open from 'open';
|
|
3
|
+
import { createEmailReport } from '../create-email-issue-for-error.js';
|
|
4
|
+
import { createGithubIssueUrlForError } from '../create-github-issue-url-for-error.js';
|
|
5
|
+
export class Feedback extends ThymianBaseCommand {
|
|
6
|
+
static CONTACT = 'c3VwcG9ydEB0aHltaWFuLmRldg==';
|
|
7
|
+
shouldSuppressFeedback() {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
async run() {
|
|
11
|
+
const lastError = await this.errorCache.read();
|
|
12
|
+
this.log('✨ Thank you for your feedback! ✨');
|
|
13
|
+
this.log();
|
|
14
|
+
if (lastError) {
|
|
15
|
+
this.log(`${oclif.ux.colorize('yellow', '⚠')} It looks like you encountered an error while running the ${oclif.ux.colorize('cyan', lastError.commandName)} command recently.`);
|
|
16
|
+
this.log();
|
|
17
|
+
const reportError = await prompts.confirm({
|
|
18
|
+
message: 'Do you want to report this error?',
|
|
19
|
+
});
|
|
20
|
+
if (reportError) {
|
|
21
|
+
await this.errorCache.reset();
|
|
22
|
+
await this.reportError(lastError);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await this.provideFeedback();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
await this.provideFeedback();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async reportError(error) {
|
|
33
|
+
const choices = [
|
|
34
|
+
{
|
|
35
|
+
name: 'Via GitHub',
|
|
36
|
+
description: 'Report the error on GitHub via a new issue.',
|
|
37
|
+
value: 'github',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Via Email',
|
|
41
|
+
description: 'Contact the Thymian Core team via Email.',
|
|
42
|
+
value: 'email',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Not at all ',
|
|
46
|
+
description: "I don't want to report this error.",
|
|
47
|
+
value: 'none',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
const choice = await prompts.select({
|
|
51
|
+
message: 'How do you want to report this error?',
|
|
52
|
+
choices,
|
|
53
|
+
});
|
|
54
|
+
this.log();
|
|
55
|
+
if (choice === 'github') {
|
|
56
|
+
await open(createGithubIssueUrlForError(error));
|
|
57
|
+
}
|
|
58
|
+
else if (choice === 'email') {
|
|
59
|
+
await open(createEmailReport(Buffer.from(Feedback.CONTACT, 'base64').toString('utf-8'), error));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async provideFeedback() {
|
|
63
|
+
const choices = [
|
|
64
|
+
{
|
|
65
|
+
name: 'Via GitHub',
|
|
66
|
+
description: 'Open a GitHub issue to provide feedback.',
|
|
67
|
+
value: 'github',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'Via Email',
|
|
71
|
+
description: 'Contact the Thymian Core team via Email.',
|
|
72
|
+
value: 'email',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Not at all ',
|
|
76
|
+
description: "I don't want to give feedback.",
|
|
77
|
+
value: 'none',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
const choice = await prompts.select({
|
|
81
|
+
message: 'How would you like to provide feedback?',
|
|
82
|
+
choices,
|
|
83
|
+
});
|
|
84
|
+
if (choice === 'github') {
|
|
85
|
+
await open('https://github.com/thymianofficial/thymian/issues/new');
|
|
86
|
+
}
|
|
87
|
+
else if (choice === 'email') {
|
|
88
|
+
const recipient = Buffer.from(Feedback.CONTACT, 'base64').toString('utf-8');
|
|
89
|
+
const subject = 'Thymian CLI Feedback';
|
|
90
|
+
const body = `Hi Support Team,\n\nI'd like to provide some feedback regarding the CLI.\n\n[Please enter your message here]\n\nBest regards,\n[Your Name]`;
|
|
91
|
+
await open(`mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/commands/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,EACL,OAAO,EACP,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AAEvF,MAAM,OAAO,QAAS,SAAQ,kBAAmC;IACrD,MAAM,CAAC,OAAO,GAAG,8BAA8B,CAAC;IAEjD,sBAAsB;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAEQ,KAAK,CAAC,GAAG;QAChB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QAE/C,IAAI,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG,EAAE,CAAC;QAEX,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CACN,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,6DAA6D,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,WAAW,CAAC,oBAAoB,CACrK,CAAC;YACF,IAAI,CAAC,GAAG,EAAE,CAAC;YAEX,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;gBACxC,OAAO,EAAE,mCAAmC;aAC7C,CAAC,CAAC;YAEH,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBAE9B,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;YAC/B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,KAAkB;QAC1C,MAAM,OAAO,GAAG;YACd;gBACE,IAAI,EAAE,YAAY;gBAClB,WAAW,EAAE,6CAA6C;gBAC1D,KAAK,EAAE,QAAQ;aAChB;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,0CAA0C;gBACvD,KAAK,EAAE,OAAO;aACf;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,WAAW,EAAE,oCAAoC;gBACjD,KAAK,EAAE,MAAM;aACd;SACO,CAAC;QAEX,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC;YAClC,OAAO,EAAE,uCAAuC;YAChD,OAAO;SACR,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,EAAE,CAAC;QAEX,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,CACR,iBAAiB,CACf,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EACzD,KAAK,CACN,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,MAAM,OAAO,GAAG;YACd;gBACE,IAAI,EAAE,YAAY;gBAClB,WAAW,EAAE,0CAA0C;gBACvD,KAAK,EAAE,QAAQ;aAChB;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,0CAA0C;gBACvD,KAAK,EAAE,OAAO;aACf;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,WAAW,EAAE,gCAAgC;gBAC7C,KAAK,EAAE,MAAM;aACd;SACO,CAAC;QAEX,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC;YAClC,OAAO,EAAE,yCAAyC;YAClD,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,uDAAuD,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAChE,OAAO,CACR,CAAC;YACF,MAAM,OAAO,GAAG,sBAAsB,CAAC;YACvC,MAAM,IAAI,GAAG,4IAA4I,CAAC;YAC1J,MAAM,IAAI,CACR,UAAU,SAAS,YAAY,kBAAkB,CAAC,OAAO,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAC9F,CAAC;QACJ,CAAC;IACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ThymianBaseCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class GenerateConfig extends ThymianBaseCommand<typeof GenerateConfig> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
"for-spec": import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private selectSpecInteractive;
|
|
13
|
+
private generateCommentedConfig;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/commands/generate/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,kBAAkB,CAC5D,OAAO,cAAc,CACtB;IACC,OAAgB,WAAW,SAC+C;IAE1E,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,KAAK;;;;;MAqBnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA2GnB,qBAAqB;IAoDnC,OAAO,CAAC,uBAAuB;CAyBhC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join, relative } from 'node:path';
|
|
4
|
+
import { defaultConfig, parseSpecFlag, ThymianBaseCommand, } from '@thymian/common-cli';
|
|
5
|
+
import { Flags, ux } from '@thymian/common-cli/oclif';
|
|
6
|
+
import { confirm, input, select } from '@thymian/common-cli/prompts';
|
|
7
|
+
import { stringify } from '@thymian/common-cli/yaml';
|
|
8
|
+
import { searchForOpenApiFiles } from '@thymian/plugin-openapi';
|
|
9
|
+
const DEFAULT_CONFIG_FILENAME = 'thymian.config.yaml';
|
|
10
|
+
export default class GenerateConfig extends ThymianBaseCommand {
|
|
11
|
+
static description = 'Generate a Thymian configuration file for a single API specification.';
|
|
12
|
+
static examples = [
|
|
13
|
+
'<%= config.bin %> generate config',
|
|
14
|
+
'<%= config.bin %> generate config --no-interactive',
|
|
15
|
+
'<%= config.bin %> generate config --output my-api.config.yaml',
|
|
16
|
+
'<%= config.bin %> generate config --for-spec openapi:./petstore.yaml',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
cwd: Flags.string({
|
|
20
|
+
default: process.cwd(),
|
|
21
|
+
description: 'Set current working directory.',
|
|
22
|
+
}),
|
|
23
|
+
interactive: Flags.boolean({
|
|
24
|
+
default: true,
|
|
25
|
+
allowNo: true,
|
|
26
|
+
description: 'Run in interactive mode. Use --no-interactive for automation.',
|
|
27
|
+
}),
|
|
28
|
+
output: Flags.string({
|
|
29
|
+
description: 'Output path for the generated configuration file. Defaults to thymian.config.yaml in the working directory.',
|
|
30
|
+
}),
|
|
31
|
+
['for-spec']: Flags.string({
|
|
32
|
+
multiple: true,
|
|
33
|
+
description: 'Specification input in the format <type>:<location>. Skips auto-detection and uses the provided spec(s) directly.',
|
|
34
|
+
helpValue: 'type:location',
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
async run() {
|
|
38
|
+
const cwd = this.flags.cwd;
|
|
39
|
+
const interactive = this.flags.interactive;
|
|
40
|
+
// Determine output path
|
|
41
|
+
let outputPath = this.flags.output
|
|
42
|
+
? join(cwd, this.flags.output)
|
|
43
|
+
: join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
44
|
+
// Continuation flow: if default config exists and no explicit output, offer named config
|
|
45
|
+
if (!this.flags.output && existsSync(outputPath)) {
|
|
46
|
+
if (interactive) {
|
|
47
|
+
this.log(`A configuration file already exists at ${outputPath}.`);
|
|
48
|
+
const customPath = await input({
|
|
49
|
+
message: 'Enter a path for the new configuration file (e.g. my-api.config.yaml):',
|
|
50
|
+
});
|
|
51
|
+
if (!customPath) {
|
|
52
|
+
this.error('No path provided. Aborting.', { exit: 1 });
|
|
53
|
+
}
|
|
54
|
+
outputPath = join(cwd, customPath);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this.error(`Configuration file already exists at ${outputPath}. Use --output to specify a different path.`, { exit: 1 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Guard against overwriting an existing file at the resolved output path.
|
|
61
|
+
// The default-config-exists case is already handled above; this covers
|
|
62
|
+
// --output pointing to an existing file or an interactive custom path that
|
|
63
|
+
// already exists.
|
|
64
|
+
if (existsSync(outputPath)) {
|
|
65
|
+
if (interactive) {
|
|
66
|
+
const overwrite = await confirm({
|
|
67
|
+
message: `File already exists at ${outputPath}. Overwrite?`,
|
|
68
|
+
default: false,
|
|
69
|
+
});
|
|
70
|
+
if (!overwrite) {
|
|
71
|
+
this.error('Aborted to avoid overwriting existing file.', {
|
|
72
|
+
exit: 1,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.error(`File already exists at ${outputPath}. Use a different --output path or remove the existing file.`, { exit: 1 });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Resolve specification: --for-spec flag takes priority over auto-detection
|
|
81
|
+
let selectedSpec;
|
|
82
|
+
if (this.flags['for-spec'] && this.flags['for-spec'].length > 0) {
|
|
83
|
+
// Use the first --for-spec value for the config file
|
|
84
|
+
selectedSpec = parseSpecFlag(this.flags['for-spec'][0]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Auto-detect OpenAPI files
|
|
88
|
+
const detectedFiles = await searchForOpenApiFiles(cwd);
|
|
89
|
+
if (interactive) {
|
|
90
|
+
const selectedPath = await this.selectSpecInteractive(detectedFiles);
|
|
91
|
+
selectedSpec = { type: 'openapi', location: selectedPath };
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (detectedFiles.length === 0) {
|
|
95
|
+
this.error('No OpenAPI/Swagger files detected. Provide a specification manually with --for-spec.', { exit: 1 });
|
|
96
|
+
}
|
|
97
|
+
if (detectedFiles.length === 1) {
|
|
98
|
+
selectedSpec = { type: 'openapi', location: detectedFiles[0] };
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// In non-interactive mode with multiple specs, use the first one
|
|
102
|
+
selectedSpec = { type: 'openapi', location: detectedFiles[0] };
|
|
103
|
+
this.log(`Multiple specification files detected. Using the first one: ${detectedFiles[0]}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Build config from defaults
|
|
108
|
+
const config = {
|
|
109
|
+
...defaultConfig,
|
|
110
|
+
specifications: [selectedSpec],
|
|
111
|
+
};
|
|
112
|
+
// Generate well-commented YAML
|
|
113
|
+
const yamlContent = this.generateCommentedConfig(config, String(selectedSpec.location));
|
|
114
|
+
await writeFile(outputPath, yamlContent, { encoding: 'utf-8' });
|
|
115
|
+
this.log(`${ux.colorize('green', 'Configuration written to')} ${relative(cwd, outputPath)}`);
|
|
116
|
+
}
|
|
117
|
+
async selectSpecInteractive(detectedFiles) {
|
|
118
|
+
if (detectedFiles.length === 0) {
|
|
119
|
+
// No files detected — ask for manual entry
|
|
120
|
+
this.log('No OpenAPI/Swagger specification files detected.');
|
|
121
|
+
const manualPath = await input({
|
|
122
|
+
message: 'Enter the path to your OpenAPI specification file:',
|
|
123
|
+
});
|
|
124
|
+
if (!manualPath) {
|
|
125
|
+
this.error('No specification path provided. Aborting.', { exit: 1 });
|
|
126
|
+
}
|
|
127
|
+
return manualPath;
|
|
128
|
+
}
|
|
129
|
+
if (detectedFiles.length === 1) {
|
|
130
|
+
// Single file — confirm
|
|
131
|
+
const useDetected = await confirm({
|
|
132
|
+
message: `Detected specification: ${detectedFiles[0]}. Use this file?`,
|
|
133
|
+
default: true,
|
|
134
|
+
});
|
|
135
|
+
if (useDetected) {
|
|
136
|
+
return detectedFiles[0];
|
|
137
|
+
}
|
|
138
|
+
// User declined — ask for manual entry
|
|
139
|
+
const manualPath = await input({
|
|
140
|
+
message: 'Enter the path to your OpenAPI specification file:',
|
|
141
|
+
});
|
|
142
|
+
if (!manualPath) {
|
|
143
|
+
this.error('No specification path provided. Aborting.', { exit: 1 });
|
|
144
|
+
}
|
|
145
|
+
return manualPath;
|
|
146
|
+
}
|
|
147
|
+
// Multiple files — selection list
|
|
148
|
+
const selected = await select({
|
|
149
|
+
message: 'Multiple specification files detected. Select one:',
|
|
150
|
+
choices: detectedFiles.map((file) => ({
|
|
151
|
+
name: file,
|
|
152
|
+
value: file,
|
|
153
|
+
})),
|
|
154
|
+
});
|
|
155
|
+
return selected;
|
|
156
|
+
}
|
|
157
|
+
generateCommentedConfig(config, specPath) {
|
|
158
|
+
const yaml = stringify(config);
|
|
159
|
+
// Prepend a comment header explaining the config
|
|
160
|
+
const header = [
|
|
161
|
+
'# Thymian Configuration',
|
|
162
|
+
'# Generated by `thymian generate config`',
|
|
163
|
+
'#',
|
|
164
|
+
`# Specification: ${specPath}`,
|
|
165
|
+
'#',
|
|
166
|
+
'# For documentation, see: https://thymian.dev/docs/configuration',
|
|
167
|
+
'#',
|
|
168
|
+
'# Run `thymian lint` to validate your API specification.',
|
|
169
|
+
'# Run `thymian test` to test a live API against the specification.',
|
|
170
|
+
'#',
|
|
171
|
+
'',
|
|
172
|
+
].join('\n');
|
|
173
|
+
return header + yaml;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/commands/generate/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,aAAa,EACb,aAAa,EACb,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAEtD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,kBAE3C;IACC,MAAM,CAAU,WAAW,GACzB,uEAAuE,CAAC;IAE1E,MAAM,CAAU,QAAQ,GAAG;QACzB,mCAAmC;QACnC,oDAAoD;QACpD,+DAA+D;QAC/D,sEAAsE;KACvE,CAAC;IAEF,MAAM,CAAU,KAAK,GAAG;QACtB,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;YACtB,WAAW,EAAE,gCAAgC;SAC9C,CAAC;QACF,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC;YACzB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;YACb,WAAW,EACT,+DAA+D;SAClE,CAAC;QACF,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YACnB,WAAW,EACT,6GAA6G;SAChH,CAAC;QACF,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;YACzB,QAAQ,EAAE,IAAI;YACd,WAAW,EACT,mHAAmH;YACrH,SAAS,EAAE,eAAe;SAC3B,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;QAE3C,wBAAwB;QACxB,IAAI,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM;YAChC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAC9B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAEvC,yFAAyF;QACzF,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACjD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,GAAG,CAAC,0CAA0C,UAAU,GAAG,CAAC,CAAC;gBAClE,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC;oBAC7B,OAAO,EACL,wEAAwE;iBAC3E,CAAC,CAAC;gBAEH,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,IAAI,CAAC,KAAK,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;gBACzD,CAAC;gBAED,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CACR,wCAAwC,UAAU,6CAA6C,EAC/F,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;YACJ,CAAC;QACH,CAAC;QAED,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,kBAAkB;QAClB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;oBAC9B,OAAO,EAAE,0BAA0B,UAAU,cAAc;oBAC3D,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,IAAI,CAAC,KAAK,CAAC,6CAA6C,EAAE;wBACxD,IAAI,EAAE,CAAC;qBACR,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CACR,0BAA0B,UAAU,8DAA8D,EAClG,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;YACJ,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,IAAI,YAA8C,CAAC;QAEnD,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChE,qDAAqD;YACrD,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,4BAA4B;YAC5B,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAEvD,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;gBACrE,YAAY,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC/B,IAAI,CAAC,KAAK,CACR,sFAAsF,EACtF,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;gBACJ,CAAC;gBAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC/B,YAAY,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAE,EAAE,CAAC;gBAClE,CAAC;qBAAM,CAAC;oBACN,iEAAiE;oBACjE,YAAY,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAE,EAAE,CAAC;oBAChE,IAAI,CAAC,GAAG,CACN,+DAA+D,aAAa,CAAC,CAAC,CAAC,EAAE,CAClF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,MAAM,MAAM,GAAG;YACb,GAAG,aAAa;YAChB,cAAc,EAAE,CAAC,YAAY,CAAC;SAC/B,CAAC;QAEF,+BAA+B;QAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,uBAAuB,CAC9C,MAAM,EACN,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAC9B,CAAC;QAEF,MAAM,SAAS,CAAC,UAAU,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhE,IAAI,CAAC,GAAG,CACN,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,0BAA0B,CAAC,IAAI,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,CACnF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,qBAAqB,CACjC,aAAuB;QAEvB,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,2CAA2C;YAC3C,IAAI,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;YAC7D,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC;gBAC7B,OAAO,EAAE,oDAAoD;aAC9D,CAAC,CAAC;YAEH,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,wBAAwB;YACxB,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC;gBAChC,OAAO,EAAE,2BAA2B,aAAa,CAAC,CAAC,CAAC,kBAAkB;gBACtE,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,aAAa,CAAC,CAAC,CAAE,CAAC;YAC3B,CAAC;YAED,uCAAuC;YACvC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC;gBAC7B,OAAO,EAAE,oDAAoD;aAC9D,CAAC,CAAC;YAEH,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,kCAAkC;QAClC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;YAC5B,OAAO,EAAE,oDAAoD;YAC7D,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACpC,IAAI,EAAE,IAAI;gBACV,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,uBAAuB,CAC7B,MAEC,EACD,QAAgB;QAEhB,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAE/B,iDAAiD;QACjD,MAAM,MAAM,GAAG;YACb,yBAAyB;YACzB,0CAA0C;YAC1C,GAAG;YACH,oBAAoB,QAAQ,EAAE;YAC9B,GAAG;YACH,kEAAkE;YAClE,GAAG;YACH,0DAA0D;YAC1D,oEAAoE;YACpE,GAAG;YACH,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,OAAO,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SAC+B;IAE1D,OAAgB,QAAQ,WAItB;IAEa,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAwBpC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
|
|
2
|
+
export default class Lint extends BaseCliRunCommand {
|
|
3
|
+
static description = 'Lint API specifications against configured rule sets.';
|
|
4
|
+
static examples = [
|
|
5
|
+
'<%= config.bin %> <%= command.id %>',
|
|
6
|
+
'<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --rule-set @thymian/rules-rfc-9110',
|
|
8
|
+
];
|
|
9
|
+
async run() {
|
|
10
|
+
const specifications = this.thymianConfig.specifications ?? [];
|
|
11
|
+
const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
|
|
12
|
+
const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
|
|
13
|
+
const outcome = await this.thymian.run(async () => {
|
|
14
|
+
return await this.thymian.lint({
|
|
15
|
+
specification: specifications,
|
|
16
|
+
rules: ruleSets,
|
|
17
|
+
rulesConfig: this.thymianConfig.rules,
|
|
18
|
+
ruleFilter: createSeverityRuleFilter(ruleSeverity),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
handleWorkflowOutcome(this, outcome);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GACzB,uDAAuD,CAAC;IAE1D,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,mEAAmE;QACnE,wEAAwE;KACzE,CAAC;IAEO,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC7B,aAAa,EAAE,cAAc;gBAC7B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;aACnD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/plugins/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SAA0C;IAExD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAWlC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EOL } from 'node:os';
|
|
2
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
3
|
+
import { ux } from '@thymian/common-cli/oclif';
|
|
4
|
+
export default class List extends BaseCliRunCommand {
|
|
5
|
+
static description = 'List all registered Thymian plugins.';
|
|
6
|
+
async run() {
|
|
7
|
+
await this.thymian.run(() => {
|
|
8
|
+
this.log(this.thymian.plugins
|
|
9
|
+
.map((plugin) => ux.colorize(this.config?.theme?.topic, plugin.plugin.name))
|
|
10
|
+
.join(EOL));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/plugins/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AAE/C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GAAG,sCAAsC,CAAC;IAE9D,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,OAAO,CAAC,OAAO;iBACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACd,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAC3D;iBACA,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AAM7E,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,iBAAiB,CACjE,OAAO,oBAAoB,CAC5B;IACgB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBpC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseCliRunCommand, thymianConfigSchema } from '@thymian/common-cli';
|
|
2
|
+
const configSchema = {
|
|
3
|
+
...thymianConfigSchema,
|
|
4
|
+
};
|
|
5
|
+
export default class GenerateConfigSchema extends BaseCliRunCommand {
|
|
6
|
+
async run() {
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
8
|
+
// @ts-expect-error
|
|
9
|
+
configSchema.properties.plugins['properties'] = {};
|
|
10
|
+
for (const { plugin } of this.thymian.plugins) {
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
12
|
+
// @ts-expect-error
|
|
13
|
+
configSchema.properties.plugins['properties'][plugin.name] = {
|
|
14
|
+
type: 'object',
|
|
15
|
+
required: ['options'],
|
|
16
|
+
properties: {
|
|
17
|
+
path: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
verbose: {
|
|
21
|
+
type: 'boolean',
|
|
22
|
+
},
|
|
23
|
+
options: plugin.options,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
this.log(JSON.stringify(configSchema, null, 2));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,MAAM,YAAY,GAAG;IACnB,GAAG,mBAAmB;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,iBAEjD;IACU,KAAK,CAAC,GAAG;QAChB,6DAA6D;QAC7D,mBAAmB;QACnB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;QAEnD,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9C,6DAA6D;YAC7D,mBAAmB;YACnB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;gBAC3D,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,SAAS,CAAC;gBACrB,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;qBACf;oBACD,OAAO,EAAE;wBACP,IAAI,EAAE,SAAS;qBAChB;oBACD,OAAO,EAAE,MAAM,CAAC,OAAO;iBACxB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class Serve extends BaseCliRunCommand<typeof Serve> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static requiresSpecifications: boolean;
|
|
6
|
+
run(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAAiB,CAAC,OAAO,KAAK,CAAC;IAChE,OAAgB,WAAW,SAAgC;IAC3D,OAAgB,QAAQ,WAA2C;IACnE,OAAgB,sBAAsB,UAAS;IAEhC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAiCpC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class Serve extends BaseCliRunCommand {
|
|
3
|
+
static description = 'Run Thymian in serve mode.';
|
|
4
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
5
|
+
static requiresSpecifications = false;
|
|
6
|
+
async run() {
|
|
7
|
+
const close = async (code = 0) => {
|
|
8
|
+
this.debug('Closing Thymian.');
|
|
9
|
+
await this.thymian.close();
|
|
10
|
+
process.exit(code);
|
|
11
|
+
};
|
|
12
|
+
process.on('SIGINT', close);
|
|
13
|
+
this.thymian.emitter.on('core.exit', async ({ code }) => {
|
|
14
|
+
await this.thymian.close();
|
|
15
|
+
await close(code);
|
|
16
|
+
});
|
|
17
|
+
const quit = 'q';
|
|
18
|
+
if (process.stdin.isTTY) {
|
|
19
|
+
process.stdin.setRawMode(true);
|
|
20
|
+
}
|
|
21
|
+
process.stdin.resume();
|
|
22
|
+
process.stdin.on('data', async (data) => {
|
|
23
|
+
if (data.toString() === quit) {
|
|
24
|
+
await close(0);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
await this.thymian.ready();
|
|
28
|
+
this.log(`Thymian is now in "serve" mode. Press "${quit}" to exit.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAA+B;IAChE,MAAM,CAAU,WAAW,GAAG,4BAA4B,CAAC;IAC3D,MAAM,CAAU,QAAQ,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnE,MAAM,CAAU,sBAAsB,GAAG,KAAK,CAAC;IAEtC,KAAK,CAAC,GAAG;QAChB,MAAM,KAAK,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE;YAC/B,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAE/B,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAE3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE5B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACtD,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAE3B,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,GAAG,CAAC;QAEjB,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtC,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAE3B,IAAI,CAAC,GAAG,CAAC,0CAA0C,IAAI,YAAY,CAAC,CAAC;IACvE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCliRunCommand } from '@thymian/common-cli';
|
|
2
|
+
export default class Test extends BaseCliRunCommand<typeof Test> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
"target-url": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAO7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SACwD;IAEnF,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,KAAK;;MAKnB;IAEa,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2BpC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
|
|
2
|
+
import { Flags } from '@thymian/common-cli/oclif';
|
|
3
|
+
export default class Test extends BaseCliRunCommand {
|
|
4
|
+
static description = 'Test API specifications by running live requests against configured rule sets.';
|
|
5
|
+
static examples = [
|
|
6
|
+
'<%= config.bin %> <%= command.id %>',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --rule-set @thymian/rules-rfc-9110',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> --target-url http://localhost:8080',
|
|
10
|
+
];
|
|
11
|
+
static flags = {
|
|
12
|
+
['target-url']: Flags.string({
|
|
13
|
+
description: 'Override the target URL for all test requests. When set, all requests are sent to this origin instead of the servers defined in the specification.',
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const specifications = this.thymianConfig.specifications ?? [];
|
|
18
|
+
const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
|
|
19
|
+
const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
|
|
20
|
+
const targetUrl = this.flags['target-url'] ?? this.thymianConfig.targetUrl;
|
|
21
|
+
const outcome = await this.thymian.run(async () => {
|
|
22
|
+
return await this.thymian.test({
|
|
23
|
+
specification: specifications,
|
|
24
|
+
rules: ruleSets,
|
|
25
|
+
rulesConfig: this.thymianConfig.rules,
|
|
26
|
+
ruleFilter: createSeverityRuleFilter(ruleSeverity),
|
|
27
|
+
targetUrl,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
handleWorkflowOutcome(this, outcome);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAMlD,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GACzB,gFAAgF,CAAC;IAEnF,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,mEAAmE;QACnE,wEAAwE;QACxE,wEAAwE;KACzE,CAAC;IAEF,MAAM,CAAU,KAAK,GAAG;QACtB,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;YAC3B,WAAW,EACT,oJAAoJ;SACvJ,CAAC;KACH,CAAC;IAEO,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;QAE3E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC7B,aAAa,EAAE,cAAc;gBAC7B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;gBAClD,SAAS;aACV,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-email-issue-for-error.d.ts","sourceRoot":"","sources":["../src/create-email-issue-for-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,WAAW,GACrB,MAAM,CAiCR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function createEmailReport(recipient, errorData) {
|
|
2
|
+
const subject = `CLI Error Report: ${errorData.commandName}`;
|
|
3
|
+
const body = `
|
|
4
|
+
Hi Support Team,
|
|
5
|
+
|
|
6
|
+
I'd like to provide some feedback regarding the CLI.
|
|
7
|
+
|
|
8
|
+
${errorData
|
|
9
|
+
? `--- ERROR REPORT ---
|
|
10
|
+
Command: ${errorData.commandName}
|
|
11
|
+
Timestamp: ${new Date(errorData.timestamp).toLocaleString()}
|
|
12
|
+
|
|
13
|
+
ENVIRONMENT:
|
|
14
|
+
- CLI: ${errorData.version.cliVersion}
|
|
15
|
+
- Node: ${errorData.version.nodeVersion}
|
|
16
|
+
- OS: ${errorData.version.osVersion} (${errorData.version.architecture})
|
|
17
|
+
|
|
18
|
+
PLUGINS:
|
|
19
|
+
${errorData.pluginVersions.map((p) => ` - ${p.name}: ${p.version}`).join('\n')}
|
|
20
|
+
|
|
21
|
+
STACKTRACE:
|
|
22
|
+
${errorData.stack?.replaceAll(process.env.HOME || '', '~') || 'No stacktrace available'}
|
|
23
|
+
--------------------`
|
|
24
|
+
: 'Description of my feedback:\n\n[Please enter your message here]'}
|
|
25
|
+
|
|
26
|
+
Best regards,
|
|
27
|
+
[Your Name]
|
|
28
|
+
`.trim();
|
|
29
|
+
return `mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=create-email-issue-for-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-email-issue-for-error.js","sourceRoot":"","sources":["../src/create-email-issue-for-error.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,SAAsB;IAEtB,MAAM,OAAO,GAAG,qBAAqB,SAAS,CAAC,WAAW,EAAE,CAAC;IAE7D,MAAM,IAAI,GAAG;;;;;EAMb,SAAS;QACP,CAAC,CAAC;WACK,SAAS,CAAC,WAAW;aACnB,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE;;;SAGlD,SAAS,CAAC,OAAO,CAAC,UAAU;UAC3B,SAAS,CAAC,OAAO,CAAC,WAAW;QAC/B,SAAS,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,OAAO,CAAC,YAAY;;;EAGpE,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG7E,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,IAAI,yBAAyB;qBAClE;QACjB,CAAC,CAAC,iEACN;;;;CAIC,CAAC,IAAI,EAAE,CAAC;IAEP,OAAO,UAAU,SAAS,YAAY,kBAAkB,CAAC,OAAO,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-github-issue-url-for-error.d.ts","sourceRoot":"","sources":["../src/create-github-issue-url-for-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAmDvE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function createGithubIssueUrlForError(error) {
|
|
2
|
+
const baseUrl = 'https://github.com/thymianofficial/thymian/issues/new';
|
|
3
|
+
const title = `${error.name} while running in command \`${error.commandName}\``;
|
|
4
|
+
const pluginTable = error?.pluginVersions
|
|
5
|
+
.map((p) => `| ${p.name} | ${p.version} |`)
|
|
6
|
+
.join('\n') || '| none | - |';
|
|
7
|
+
const body = `
|
|
8
|
+
### 📝 Description
|
|
9
|
+
### 💻 Environment
|
|
10
|
+
- **CLI Version:** \`${error.version.cliVersion || 'N/A'}\`
|
|
11
|
+
- **Node Version:** \`${error.version.nodeVersion || 'N/A'}\`
|
|
12
|
+
- **OS:** \`${error?.version.osVersion || 'N/A'}\` (${error.version.architecture})
|
|
13
|
+
- **Command:** \`${error?.commandName} || ''}\`
|
|
14
|
+
- **Timestamp:** ${error ? new Date(error.timestamp).toLocaleString() : 'N/A'}
|
|
15
|
+
|
|
16
|
+
<details>
|
|
17
|
+
<summary><b>🔌 Installed Plugins</b></summary>
|
|
18
|
+
|
|
19
|
+
| Plugin | Version |
|
|
20
|
+
| :--- | :--- |
|
|
21
|
+
${pluginTable}
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
### 🔍 Error Details
|
|
25
|
+
${error.stack
|
|
26
|
+
? `
|
|
27
|
+
<details>
|
|
28
|
+
<summary><b>Click to expand Stacktrace</b></summary>
|
|
29
|
+
|
|
30
|
+
\`\`\`text
|
|
31
|
+
${error.stack.replaceAll(process.env.HOME || '', '~')}
|
|
32
|
+
\`\`\`
|
|
33
|
+
</details>
|
|
34
|
+
`
|
|
35
|
+
: '_No stacktrace available._'}
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
*Reported via \`thymian feedback\`*`.trim();
|
|
39
|
+
const url = new URL(baseUrl);
|
|
40
|
+
url.searchParams.set('title', title);
|
|
41
|
+
url.searchParams.set('body', body);
|
|
42
|
+
url.searchParams.set('labels', 'bug');
|
|
43
|
+
return url.toString();
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=create-github-issue-url-for-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-github-issue-url-for-error.js","sourceRoot":"","sources":["../src/create-github-issue-url-for-error.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,4BAA4B,CAAC,KAAkB;IAC7D,MAAM,OAAO,GAAG,uDAAuD,CAAC;IAExE,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,+BAA+B,KAAK,CAAC,WAAW,IAAI,CAAC;IAEhF,MAAM,WAAW,GACf,KAAK,EAAE,cAAc;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,IAAI,CAAC;SAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC;IAElC,MAAM,IAAI,GAAG;;;uBAGQ,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,KAAK;wBAChC,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,KAAK;cAC5C,KAAK,EAAE,OAAO,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,CAAC,OAAO,CAAC,YAAY;mBAC7D,KAAK,EAAE,WAAW;mBAClB,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK;;;;;;;EAO3E,WAAW;;;;EAKX,KAAK,CAAC,KAAK;QACT,CAAC,CAAC;;;;;EAKJ,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC;;;CAGpD;QACG,CAAC,CAAC,4BACN;;;oCAGoC,CAAC,IAAI,EAAE,CAAC;IAE1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAEtC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/hooks/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEtE,QAAA,MAAM,IAAI,EAAE,mBAKX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { oclif } from '@thymian/common-cli';
|
|
2
|
+
const hook = async () => {
|
|
3
|
+
const message = `${oclif.ux.colorize('blueBright', `🚀 Tip: Found a bug or wanna give feedback? Run ${oclif.ux.colorize('bold', 'thymian feedback')}.`)}`;
|
|
4
|
+
console.log(message);
|
|
5
|
+
console.log();
|
|
6
|
+
};
|
|
7
|
+
export default hook;
|
|
8
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/hooks/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA4B,MAAM,qBAAqB,CAAC;AAEtE,MAAM,IAAI,GAAwB,KAAK,IAAI,EAAE;IAC3C,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,oDAAoD,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;IAE3J,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thymian",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"!**/*.tsbuildinfo"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@oclif/plugin-help": "^6.2.29",
|
|
26
|
+
"@oclif/plugin-not-found": "^3.2.57",
|
|
27
|
+
"@oclif/plugin-plugins": "^5.4.43",
|
|
28
|
+
"@oclif/plugin-version": "^2.2.30",
|
|
29
|
+
"@thymian/common-cli": "0.1.0",
|
|
30
|
+
"@thymian/plugin-http-analyzer": "0.1.0",
|
|
31
|
+
"@thymian/plugin-http-linter": "0.1.0",
|
|
32
|
+
"@thymian/plugin-http-tester": "0.1.0",
|
|
33
|
+
"@thymian/plugin-openapi": "0.1.0",
|
|
34
|
+
"@thymian/plugin-reporter": "0.1.0",
|
|
35
|
+
"@thymian/plugin-request-dispatcher": "0.1.0",
|
|
36
|
+
"@thymian/plugin-sampler": "0.1.0",
|
|
37
|
+
"@thymian/plugin-websocket-proxy": "0.1.0",
|
|
38
|
+
"@thymian/rules-rfc-9110": "0.1.0",
|
|
39
|
+
"open": "^8.4.2",
|
|
40
|
+
"tslib": "^2.3.0"
|
|
41
|
+
},
|
|
42
|
+
"bin": {
|
|
43
|
+
"thymian": "./bin/run.js"
|
|
44
|
+
},
|
|
45
|
+
"oclif": {
|
|
46
|
+
"bin": "thymian",
|
|
47
|
+
"commands": "./dist/commands",
|
|
48
|
+
"hooks": {
|
|
49
|
+
"thymian.feedback": "./dist/hooks/feedback"
|
|
50
|
+
},
|
|
51
|
+
"dirname": "thymian",
|
|
52
|
+
"topicSeparator": " ",
|
|
53
|
+
"plugins": [
|
|
54
|
+
"@oclif/plugin-help",
|
|
55
|
+
"@oclif/plugin-not-found",
|
|
56
|
+
"@oclif/plugin-version",
|
|
57
|
+
"@thymian/plugin-http-linter"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@oclif/test": "^4.1.13",
|
|
62
|
+
"@types/node": "^18.19.112",
|
|
63
|
+
"tsx": "^4.20.3"
|
|
64
|
+
}
|
|
11
65
|
}
|