@thymian/plugin-http-linter 0.0.0-PLACEHOLDER

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 ADDED
@@ -0,0 +1,59 @@
1
+ <!-- HEADER:START - Do not remove or modify this section -->
2
+ <div align="center">
3
+ <img src="https://raw.githubusercontent.com/thymianofficial/thymian/main/astro-docs/src/assets/logo.svg" alt="Thymian Logo" width="200"/>
4
+
5
+ # Thymian
6
+
7
+ **Add resilience and HTTP conformance to your API development workflow**
8
+
9
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL%203.0-green.svg)](https://github.com/thymianofficial/thymian/blob/main/LICENSE)
10
+ [![CI](https://github.com/thymianofficial/thymian/actions/workflows/ci.yaml/badge.svg)](https://github.com/thymianofficial/thymian/actions/workflows/ci.yaml)
11
+ [![Documentation](https://img.shields.io/badge/docs-thymian.dev-green.svg)](https://thymian.dev)
12
+ [![Discord](https://img.shields.io/discord/1440702693768429791?logo=discord&label=Discord&color=5865F2)](https://discord.gg/TRSwCxbz9f)
13
+ [![Reddit](https://img.shields.io/badge/Reddit-ThymianOfficial-FF4500?logo=reddit)](https://www.reddit.com/r/ThymianOfficial/)
14
+ [![Twitter](https://img.shields.io/badge/Twitter-@thymiandev-1DA1F2?logo=x)](https://x.com/thymiandev)
15
+
16
+ </div>
17
+ <!-- HEADER:END -->
18
+
19
+ ## @thymian/plugin-http-linter
20
+
21
+ Performs static analysis of API specifications without making any HTTP requests. Powers `thymian lint` by loading the configured rule set and evaluating it against the parsed API description, producing educational violation reports that explain RFC semantics and real-world consequences.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @thymian/plugin-http-linter
27
+ ```
28
+
29
+ > **Getting started with Thymian?** See the [main Thymian package](https://www.npmjs.com/package/thymian) for quick installation and first-run instructions.
30
+
31
+ <!-- FOOTER:START - Do not remove or modify this section -->
32
+
33
+ ## 📚 Documentation
34
+
35
+ - **[Getting Started](https://thymian.dev/introduction/getting-started)** - Set up Thymian in minutes
36
+ - **[Documentation](https://thymian.dev)** - Comprehensive guides and API reference
37
+ - **[CLI Reference](https://thymian.dev/references/cli)** - Complete CLI command documentation
38
+ - **[HTTP Rules](https://thymian.dev/guides/http-rules/how-to-use-rules)** - Learn about HTTP conformance validation
39
+
40
+ ## 🏢 Enterprise Support
41
+
42
+ Get professional consulting and dedicated support from the creators of Thymian. We offer:
43
+
44
+ - API design and governance strategies
45
+ - HTTP standards compliance auditing
46
+ - Custom plugin development
47
+ - Custom rule development
48
+ - Team training and workshops
49
+
50
+ **[Learn more about Enterprise Support](https://thymian.dev/enterprise)** | **Email: [support@thymian.dev](mailto:support@thymian.dev)**
51
+
52
+ ---
53
+
54
+ <div align="center">
55
+
56
+ **Shipped with 🌱 by [qupaya](https://qupaya.com)**
57
+
58
+ </div>
59
+ <!-- FOOTER:END -->
@@ -0,0 +1,32 @@
1
+ import { type EvaluatedRuleViolation, type Rule, type RulesConfiguration, type SerializedThymianFormat, type ThymianPlugin, type ThymianReport } from '@thymian/core';
2
+ export { StaticApiContext } from './static-api-context.js';
3
+ declare module '@thymian/core' {
4
+ interface ThymianActions {
5
+ 'http-linter.load-rules': {
6
+ event: {
7
+ rules: string[];
8
+ };
9
+ response: void;
10
+ };
11
+ 'http-linter.rules': {
12
+ event: never;
13
+ response: Rule[];
14
+ };
15
+ 'http-linter.lint-static': {
16
+ event: {
17
+ format: SerializedThymianFormat;
18
+ rules?: Rule[];
19
+ rulesConfig?: RulesConfiguration;
20
+ };
21
+ response: {
22
+ reports: ThymianReport[];
23
+ violations: EvaluatedRuleViolation[];
24
+ valid: boolean;
25
+ };
26
+ };
27
+ }
28
+ }
29
+ export declare function createHttpLinterPlugin(pluginName?: string): ThymianPlugin;
30
+ export declare const httpLinterPlugin: ThymianPlugin;
31
+ export default httpLinterPlugin;
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,IAAI,EAET,KAAK,kBAAkB,EAEvB,KAAK,uBAAuB,EAG5B,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,cAAc;QACtB,wBAAwB,EAAE;YACxB,KAAK,EAAE;gBAAE,KAAK,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC;YAC3B,QAAQ,EAAE,IAAI,CAAC;SAChB,CAAC;QAEF,mBAAmB,EAAE;YACnB,KAAK,EAAE,KAAK,CAAC;YACb,QAAQ,EAAE,IAAI,EAAE,CAAC;SAClB,CAAC;QAEF,yBAAyB,EAAE;YACzB,KAAK,EAAE;gBACL,MAAM,EAAE,uBAAuB,CAAC;gBAChC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;gBACf,WAAW,CAAC,EAAE,kBAAkB,CAAC;aAClC,CAAC;YACF,QAAQ,EAAE;gBACR,OAAO,EAAE,aAAa,EAAE,CAAC;gBACzB,UAAU,EAAE,sBAAsB,EAAE,CAAC;gBACrC,KAAK,EAAE,OAAO,CAAC;aAChB,CAAC;SACH,CAAC;KACH;CACF;AAyBD,wBAAgB,sBAAsB,CACpC,UAAU,SAAgC,GACzC,aAAa,CA0Ef;AAED,eAAO,MAAM,gBAAgB,eAA2B,CAAC;AAEzD,eAAe,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ import { runRules, ThymianFormat, } from '@thymian/core';
2
+ import { StaticApiContext } from './static-api-context.js';
3
+ export { StaticApiContext } from './static-api-context.js';
4
+ function createStaticLinterAdapter(logger, reportFn, format, rulesConfig) {
5
+ return {
6
+ errorName: 'StaticLinterError',
7
+ mode: 'static',
8
+ getRuleFn: (rule) => rule.lintRule,
9
+ createContext: (_rule, options) => new StaticApiContext(format, logger, reportFn, (options ?? {}).skipOrigins),
10
+ };
11
+ }
12
+ export function createHttpLinterPlugin(pluginName = '@thymian/plugin-http-linter') {
13
+ return {
14
+ name: pluginName,
15
+ version: '0.x',
16
+ actions: {
17
+ listensOn: ['core.lint'],
18
+ },
19
+ async plugin(emitter, logger) {
20
+ emitter.onAction('core.lint', async ({ format, rules = [], rulesConfig = {} }, ctx) => {
21
+ const thymianFormat = ThymianFormat.import(format);
22
+ const reportFn = (report) => emitter.emit('core.report', report);
23
+ const { violations, statistics } = await runRules(logger, rules, thymianFormat, rulesConfig, createStaticLinterAdapter(logger, reportFn, thymianFormat, rulesConfig));
24
+ ctx.reply({
25
+ source: pluginName,
26
+ status: violations.length === 0 ? 'success' : 'failed',
27
+ violations,
28
+ statistics,
29
+ });
30
+ });
31
+ emitter.onAction('http-linter.lint-static', async ({ format, rules = [], rulesConfig = {} }, ctx) => {
32
+ const thymianFormat = ThymianFormat.import(format);
33
+ const reports = [];
34
+ const reportFn = (report) => reports.push(report);
35
+ const { violations } = await runRules(logger, rules, thymianFormat, rulesConfig, createStaticLinterAdapter(logger, reportFn, thymianFormat, rulesConfig));
36
+ ctx.reply({
37
+ reports,
38
+ violations,
39
+ valid: violations.length === 0,
40
+ });
41
+ });
42
+ emitter.onAction('http-linter.load-rules', async (_, ctx) => {
43
+ ctx.reply();
44
+ });
45
+ emitter.onAction('http-linter.rules', (_, ctx) => {
46
+ ctx.reply([]);
47
+ });
48
+ },
49
+ };
50
+ }
51
+ export const httpLinterPlugin = createHttpLinterPlugin();
52
+ export default httpLinterPlugin;
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type CommonHttpRequest, type CommonHttpResponse, type HttpFilterExpression, type LintContext, type Logger, type PartialBy, type ReportFn, type RuleFnResult, type RuleViolation, type RuleViolationLocation, ThymianFormat, type ThymianHttpRequest, type ThymianHttpResponse, type ValidationFn } from '@thymian/core';
2
+ export declare class StaticApiContext implements LintContext {
3
+ private readonly logger;
4
+ private readonly skippedOrigins;
5
+ readonly format: ThymianFormat;
6
+ readonly report: ReportFn;
7
+ private readonly violations;
8
+ constructor(format: ThymianFormat, logger: Logger, report?: ReportFn, skippedOrigins?: string[]);
9
+ reportViolation(violation: RuleViolation): void;
10
+ validateCommonHttpTransactions(filter: HttpFilterExpression, validate?: ValidationFn<[
11
+ CommonHttpRequest,
12
+ CommonHttpResponse,
13
+ RuleViolationLocation
14
+ ]> | HttpFilterExpression): RuleFnResult;
15
+ validateGroupedCommonHttpTransactions(filter: HttpFilterExpression, groupBy: HttpFilterExpression, validationFn: ValidationFn<[
16
+ string,
17
+ [
18
+ CommonHttpRequest,
19
+ CommonHttpResponse,
20
+ RuleViolationLocation
21
+ ][]
22
+ ], RuleViolation | undefined>): RuleFnResult;
23
+ validateHttpTransactions(filterFn: (req: ThymianHttpRequest, res: ThymianHttpResponse, responses: ThymianHttpResponse[]) => boolean, validationFn?: (req: ThymianHttpRequest, res: ThymianHttpResponse, responses: ThymianHttpResponse[]) => PartialBy<RuleViolation, 'location'> | boolean): RuleFnResult;
24
+ }
25
+ //# sourceMappingURL=static-api-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-api-context.d.ts","sourceRoot":"","sources":["../src/static-api-context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EAEvB,KAAK,oBAAoB,EAEzB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAKxB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAKvB,qBAAa,gBAAiB,YAAW,WAAW;IAOhD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IARjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;gBAGhD,MAAM,EAAE,aAAa,EACJ,MAAM,EAAE,MAAM,EAC/B,MAAM,GAAE,QAA0B,EACjB,cAAc,GAAE,MAAM,EAAO;IAkBhD,eAAe,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAI/C,8BAA8B,CAC5B,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,GACJ,YAAY,CACV;QAAC,iBAAiB;QAAE,kBAAkB;QAAE,qBAAqB;KAAC,CAC/D,GACD,oBAA6B,GAChC,YAAY;IA2Df,qCAAqC,CACnC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,oBAAoB,EAC7B,YAAY,EAAE,YAAY,CACxB;QACE,MAAM;QACN;YAAC,iBAAiB;YAAE,kBAAkB;YAAE,qBAAqB;SAAC,EAAE;KACjE,EACD,aAAa,GAAG,SAAS,CAC1B,GACA,YAAY;IA+Cf,wBAAwB,CACtB,QAAQ,EAAE,CACR,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,mBAAmB,EACxB,SAAS,EAAE,mBAAmB,EAAE,KAC7B,OAAO,EACZ,YAAY,GAAE,CACZ,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,mBAAmB,EACxB,SAAS,EAAE,mBAAmB,EAAE,KAC7B,SAAS,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,OAAkB,GAC7D,YAAY;CA+ChB"}
@@ -0,0 +1,137 @@
1
+ import { createRegExpFromOriginWildcard, isNodeType, ThymianFormat, thymianRequestToOrigin, thymianToCommonHttpRequest, thymianToCommonHttpResponse, } from '@thymian/core';
2
+ import { httpFilterExpressionToFilter } from './visitors/http-filter-expression-to-filter.js';
3
+ import { httpFilterToGroupByFn } from './visitors/http-filter-to-static-by-fn.js';
4
+ export class StaticApiContext {
5
+ logger;
6
+ skippedOrigins;
7
+ format;
8
+ report;
9
+ violations = [];
10
+ constructor(format, logger, report = () => undefined, skippedOrigins = []) {
11
+ this.logger = logger;
12
+ this.skippedOrigins = skippedOrigins;
13
+ this.report = report;
14
+ if (skippedOrigins.length === 0) {
15
+ this.format = format;
16
+ }
17
+ else {
18
+ const regExps = skippedOrigins.map(createRegExpFromOriginWildcard);
19
+ this.format = format.filter(({ thymianReq }) => !regExps.some((regExp) => regExp.test(thymianRequestToOrigin(thymianReq))));
20
+ }
21
+ }
22
+ reportViolation(violation) {
23
+ this.violations.push(violation);
24
+ }
25
+ validateCommonHttpTransactions(filter, validate = filter) {
26
+ const filterFn = httpFilterExpressionToFilter(filter);
27
+ return this.format
28
+ .getThymianHttpTransactions()
29
+ .filter((transaction) => filterFn(transaction, this.format))
30
+ .reduce((violations, transaction) => {
31
+ if (typeof validate === 'function') {
32
+ const validationResult = validate(thymianToCommonHttpRequest(transaction.thymianReq, transaction.thymianReqId), thymianToCommonHttpResponse(transaction.thymianRes, transaction.thymianResId), {
33
+ elementType: 'edge',
34
+ elementId: transaction.transactionId,
35
+ });
36
+ if (typeof validationResult === 'boolean' && validationResult) {
37
+ violations.push({
38
+ location: {
39
+ elementType: 'edge',
40
+ elementId: transaction.transactionId,
41
+ },
42
+ });
43
+ }
44
+ if (validationResult && typeof validationResult === 'object') {
45
+ violations.push({
46
+ location: {
47
+ elementType: 'edge',
48
+ elementId: transaction.transactionId,
49
+ },
50
+ ...validationResult,
51
+ });
52
+ }
53
+ }
54
+ else {
55
+ const validateFn = httpFilterExpressionToFilter(validate);
56
+ if (validateFn(transaction, this.format)) {
57
+ violations.push({
58
+ location: {
59
+ elementType: 'edge',
60
+ elementId: transaction.transactionId,
61
+ pointer: '',
62
+ },
63
+ });
64
+ }
65
+ }
66
+ return violations;
67
+ }, [])
68
+ .concat(this.violations);
69
+ }
70
+ validateGroupedCommonHttpTransactions(filter, groupBy, validationFn) {
71
+ const filterFn = httpFilterExpressionToFilter(filter);
72
+ const groupByFn = httpFilterToGroupByFn(groupBy);
73
+ const groups = this.format
74
+ .getThymianHttpTransactions()
75
+ .filter((t) => filterFn(t, this.format))
76
+ .reduce((groups, transaction) => {
77
+ const key = groupByFn(transaction, this.format);
78
+ (groups[key] ??= []).push(transaction);
79
+ return groups;
80
+ }, {});
81
+ return Object.entries(groups)
82
+ .reduce((violations, [key, group]) => {
83
+ const validationResult = validationFn(key, group.map(({ thymianReq, thymianRes, thymianReqId, thymianResId, transactionId, }) => [
84
+ thymianToCommonHttpRequest(thymianReq, thymianReqId),
85
+ thymianToCommonHttpResponse(thymianRes, thymianResId),
86
+ {
87
+ elementType: 'edge',
88
+ elementId: transactionId,
89
+ },
90
+ ]));
91
+ if (validationResult) {
92
+ violations.push(validationResult);
93
+ }
94
+ return violations;
95
+ }, [])
96
+ .concat(this.violations);
97
+ }
98
+ validateHttpTransactions(filterFn, validationFn = filterFn) {
99
+ return this.format.graph
100
+ .reduceNodes((violations, id, node) => {
101
+ if (!isNodeType(node, 'http-request')) {
102
+ return violations;
103
+ }
104
+ const responsesWithIds = this.format.getHttpResponsesOf(id);
105
+ const responses = responsesWithIds.map(([, res]) => res);
106
+ for (const [resId, res] of responsesWithIds) {
107
+ if (filterFn(node, res, responses)) {
108
+ const result = validationFn(node, res, responses);
109
+ const transactionId = this.format.graph.findEdge(id, resId, (_, edge) => edge.type === 'http-transaction');
110
+ if (!transactionId) {
111
+ throw new Error('Invalid HTTP transaction ID.');
112
+ }
113
+ if (typeof result === 'boolean' && result) {
114
+ violations.push({
115
+ location: {
116
+ elementType: 'edge',
117
+ elementId: transactionId,
118
+ },
119
+ });
120
+ }
121
+ else if (result) {
122
+ violations.push({
123
+ location: {
124
+ elementType: 'edge',
125
+ elementId: transactionId,
126
+ },
127
+ ...result,
128
+ });
129
+ }
130
+ }
131
+ }
132
+ return violations;
133
+ }, [])
134
+ .concat(this.violations);
135
+ }
136
+ }
137
+ //# sourceMappingURL=static-api-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-api-context.js","sourceRoot":"","sources":["../src/static-api-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type HttpFilterExpression, type ThymianFormat, type ThymianHttpTransaction } from '@thymian/core';
2
+ export type StaticFilter = (thymianTransaction: ThymianHttpTransaction, format: ThymianFormat) => boolean;
3
+ export declare function httpFilterExpressionToFilter(expression: HttpFilterExpression): StaticFilter;
4
+ //# sourceMappingURL=http-filter-expression-to-filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-filter-expression-to-filter.d.ts","sourceRoot":"","sources":["../../src/visitors/http-filter-expression-to-filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAG5B,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,YAAY,GAAG,CACzB,kBAAkB,EAAE,sBAAsB,EAC1C,MAAM,EAAE,aAAa,KAClB,OAAO,CAAC;AAqIb,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,oBAAoB,GAC/B,YAAY,CAEd"}
@@ -0,0 +1,105 @@
1
+ import { createFilterVisitor, createRegExpFromOriginWildcard, equalsIgnoreCase, thymianRequestToOrigin, visitHttpFilter, } from '@thymian/core';
2
+ const visitor = createFilterVisitor({
3
+ visitMethod({ method }) {
4
+ if (typeof method === 'undefined') {
5
+ return () => false;
6
+ }
7
+ return (transaction) => transaction.thymianReq.method.toLowerCase() === method.toLowerCase();
8
+ },
9
+ visitRequestHeader({ header }) {
10
+ if (typeof header === 'undefined') {
11
+ return () => false;
12
+ }
13
+ return (transaction) => {
14
+ return equalsIgnoreCase(header, ...Object.keys(transaction.thymianReq.headers));
15
+ };
16
+ },
17
+ visitQueryParam({ param }) {
18
+ if (typeof param === 'undefined') {
19
+ return () => false;
20
+ }
21
+ return (transaction) => {
22
+ return equalsIgnoreCase(param, ...Object.keys(transaction.thymianReq.queryParameters));
23
+ };
24
+ },
25
+ visitPath({ path }) {
26
+ if (typeof path === 'undefined') {
27
+ return () => false;
28
+ }
29
+ return (transaction) => transaction.thymianReq.path === path;
30
+ },
31
+ visitHasResponse({ filter }) {
32
+ const nestedFilter = httpFilterExpressionToFilter(filter);
33
+ return (transaction, format) => format
34
+ .getHttpResponsesOf(transaction.thymianReqId)
35
+ .some(([, , transactionId]) => {
36
+ const responseTransaction = format.getThymianHttpTransactionById(transactionId);
37
+ if (!responseTransaction) {
38
+ throw new Error('Cannot find transaction.');
39
+ }
40
+ return nestedFilter(responseTransaction, format);
41
+ });
42
+ },
43
+ visitIsAuthorized({ isAuthorized }) {
44
+ return (transaction, format) => format.requestIsSecured(transaction.thymianReqId) === isAuthorized;
45
+ },
46
+ visitOrigin({ origin }) {
47
+ return (transaction) => {
48
+ const req = transaction.thymianReq;
49
+ return `${req.protocol}://${req.host}:${req.port}` === origin;
50
+ };
51
+ },
52
+ visitHasBody({ hasBody }) {
53
+ return (transaction) => transaction.thymianReq.bodyRequired === hasBody;
54
+ },
55
+ visitPort({ port }) {
56
+ return (transaction) => transaction.thymianReq.port === port;
57
+ },
58
+ visitRequestMediaType({ mediaType }) {
59
+ return (transaction) => transaction.thymianReq.mediaType === mediaType;
60
+ },
61
+ visitUrl({ url }) {
62
+ return (transaction) => {
63
+ const req = transaction.thymianReq;
64
+ return (`${req.protocol}://${req.host}:${req.port}${req.path.startsWith('/') ? req.path : '/' + req.path}` === url);
65
+ };
66
+ },
67
+ visitProtocol({ protocol }) {
68
+ return (transaction) => transaction.thymianReq.protocol === protocol;
69
+ },
70
+ visitStatusCode({ code }) {
71
+ return (transaction) => transaction.thymianRes.statusCode === code;
72
+ },
73
+ visitHasResponseBody({ hasBody }) {
74
+ return (transaction) => !!transaction.thymianRes.schema === hasBody;
75
+ },
76
+ visitResponseHeader({ header }) {
77
+ if (typeof header === 'undefined') {
78
+ return () => false;
79
+ }
80
+ return (transaction) => equalsIgnoreCase(header, ...Object.keys(transaction.thymianRes.headers));
81
+ },
82
+ visitStatusCodeRange({ start, end }) {
83
+ return (transaction) => {
84
+ const statusCode = transaction.thymianRes.statusCode;
85
+ return (Number.isInteger(statusCode) && statusCode >= start && statusCode <= end);
86
+ };
87
+ },
88
+ visitResponseMediaType({ mediaType }) {
89
+ return (transaction) => transaction.thymianRes.mediaType === mediaType;
90
+ },
91
+ visitResponseTrailer() {
92
+ throw new Error('Response trailers are not currently supported.');
93
+ },
94
+ visitMatchesOrigin({ origin }) {
95
+ if (typeof origin !== 'string') {
96
+ return () => false;
97
+ }
98
+ const regExp = createRegExpFromOriginWildcard(origin);
99
+ return (transaction) => regExp.test(thymianRequestToOrigin(transaction.thymianReq));
100
+ },
101
+ });
102
+ export function httpFilterExpressionToFilter(expression) {
103
+ return visitHttpFilter(expression, visitor);
104
+ }
105
+ //# sourceMappingURL=http-filter-expression-to-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-filter-expression-to-filter.js","sourceRoot":"","sources":["../../src/visitors/http-filter-expression-to-filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type HttpFilterExpression, ThymianFormat, type ThymianHttpTransaction } from '@thymian/core';
2
+ export type GroupByFn = (transaction: ThymianHttpTransaction, format: ThymianFormat) => string;
3
+ export declare function httpFilterToGroupByFn(expression: HttpFilterExpression): GroupByFn;
4
+ //# sourceMappingURL=http-filter-to-static-by-fn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-filter-to-static-by-fn.d.ts","sourceRoot":"","sources":["../../src/visitors/http-filter-to-static-by-fn.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAIzB,aAAa,EACb,KAAK,sBAAsB,EAE5B,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,SAAS,GAAG,CACtB,WAAW,EAAE,sBAAsB,EACnC,MAAM,EAAE,aAAa,KAClB,MAAM,CAAC;AAmIZ,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,oBAAoB,GAC/B,SAAS,CAEX"}
@@ -0,0 +1,113 @@
1
+ import { equalsIgnoreCase, ThymianBaseError, ThymianFormat, visitHttpFilter, } from '@thymian/core';
2
+ const visitor = {
3
+ visitOrigin() {
4
+ return (transaction) => {
5
+ const req = transaction.thymianReq;
6
+ return `${req.protocol}://${req.host}:${req.port}`;
7
+ };
8
+ },
9
+ visitUrl() {
10
+ return (transaction) => {
11
+ const req = transaction.thymianReq;
12
+ return `${req.protocol}://${req.host}:${req.port}${req.path.startsWith('/') ? req.path : '/' + req.path}`;
13
+ };
14
+ },
15
+ visitPort() {
16
+ return (transaction) => String(transaction.thymianReq.port);
17
+ },
18
+ visitRequestMediaType() {
19
+ return (transaction) => transaction.thymianReq.mediaType;
20
+ },
21
+ visitResponseMediaType() {
22
+ return (transaction) => transaction.thymianRes.mediaType;
23
+ },
24
+ visitQueryParam({ param }) {
25
+ return (transaction) => {
26
+ if (!param) {
27
+ return '';
28
+ }
29
+ const keys = Object.keys(transaction.thymianReq.queryParameters);
30
+ const found = keys.find((k) => equalsIgnoreCase(k, param));
31
+ return found ? String(transaction.thymianReq.queryParameters[found]) : '';
32
+ };
33
+ },
34
+ visitIsAuthorized() {
35
+ return (transaction, format) => String(format.requestIsSecured(transaction.thymianReqId));
36
+ },
37
+ visitMethod() {
38
+ return (transaction) => transaction.thymianReq.method.toUpperCase();
39
+ },
40
+ visitRequestHeader({ header }) {
41
+ return (transaction) => {
42
+ if (!header) {
43
+ return '';
44
+ }
45
+ const keys = Object.keys(transaction.thymianReq.headers);
46
+ const found = keys.find((k) => equalsIgnoreCase(k, header));
47
+ return found ? String(transaction.thymianReq.headers[found]) : '';
48
+ };
49
+ },
50
+ visitPath() {
51
+ return (transaction) => transaction.thymianReq.path;
52
+ },
53
+ visitStatusCode() {
54
+ return (transaction) => String(transaction.thymianRes.statusCode);
55
+ },
56
+ visitResponseHeader({ header }) {
57
+ return (transaction) => {
58
+ if (!header) {
59
+ return '';
60
+ }
61
+ const keys = Object.keys(transaction.thymianRes.headers);
62
+ const found = keys.find((k) => equalsIgnoreCase(k, header));
63
+ return found ? String(transaction.thymianRes.headers[found]) : '';
64
+ };
65
+ },
66
+ visitHasResponse() {
67
+ throw new ThymianBaseError(`Unsupported group by expression "hasResponse" for grouping common HTTP transactions.`, {
68
+ name: 'UnsupportedGroupByExpression',
69
+ ref: 'https://thymian.dev/references/errors/unsupported-group-by-expression/',
70
+ suggestions: ['Use another expression type.'],
71
+ });
72
+ },
73
+ visitHasBody() {
74
+ throw new ThymianBaseError(`Unsupported group by expression "hasBody" for grouping common HTTP transactions.`, {
75
+ name: 'UnsupportedGroupByExpression',
76
+ ref: 'https://thymian.dev/references/errors/unsupported-group-by-expression/',
77
+ suggestions: ['Use another expression type.'],
78
+ });
79
+ },
80
+ visitHasResponseBody() {
81
+ throw new ThymianBaseError(`Unsupported group by expression "hasResponseBody" for grouping common HTTP transactions.`, {
82
+ name: 'UnsupportedGroupByExpression',
83
+ ref: 'https://thymian.dev/references/errors/unsupported-group-by-expression/',
84
+ suggestions: ['Use another expression type.'],
85
+ });
86
+ },
87
+ visitStatusCodeRange() {
88
+ throw new ThymianBaseError(`Unsupported group by expression "statusCodeRange" for grouping common HTTP transactions.`, {
89
+ name: 'UnsupportedGroupByExpression',
90
+ ref: 'https://thymian.dev/references/errors/unsupported-group-by-expression/',
91
+ suggestions: ['Use another expression type.'],
92
+ });
93
+ },
94
+ visitProtocol() {
95
+ return (transaction) => transaction.thymianReq.protocol;
96
+ },
97
+ visitResponseTrailer() {
98
+ throw new ThymianBaseError(`Unsupported group by expression "responseTrailer" for grouping common HTTP transactions.`, {
99
+ name: 'UnsupportedGroupByExpression',
100
+ ref: 'https://thymian.dev/references/errors/unsupported-group-by-expression/',
101
+ suggestions: ['Use another expression type.'],
102
+ });
103
+ },
104
+ visitAnd(expr) {
105
+ return (transaction, format) => expr.filters
106
+ .map((filter) => httpFilterToGroupByFn(filter)(transaction, format))
107
+ .join(' ');
108
+ },
109
+ };
110
+ export function httpFilterToGroupByFn(expression) {
111
+ return visitHttpFilter(expression, visitor);
112
+ }
113
+ //# sourceMappingURL=http-filter-to-static-by-fn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-filter-to-static-by-fn.js","sourceRoot":"","sources":["../../src/visitors/http-filter-to-static-by-fn.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@thymian/plugin-http-linter",
3
+ "version": "0.0.0-PLACEHOLDER",
4
+ "description": "Thymian plugin for static linting of API descriptions against HTTP conformance rules",
5
+ "license": "AGPL-3.0-only",
6
+ "bugs": {
7
+ "url": "https://github.com/thymianofficial/thymian/issues"
8
+ },
9
+ "homepage": "https://thymian.dev",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/thymianofficial/thymian.git",
13
+ "directory": "packages/plugin-http-linter"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "keywords": [
19
+ "thymian",
20
+ "api-linter",
21
+ "lint",
22
+ "linter",
23
+ "openapi-linter",
24
+ "rfc-9110",
25
+ "static-analysis"
26
+ ],
27
+ "main": "./dist/index.js",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "type": "module",
31
+ "exports": {
32
+ "./package.json": "./package.json",
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js",
36
+ "default": "./dist/index.js"
37
+ }
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "!**/*.tsbuildinfo"
42
+ ],
43
+ "dependencies": {
44
+ "@thymian/core": "0.0.0-PLACEHOLDER",
45
+ "tslib": "^2.3.0"
46
+ },
47
+ "devDependencies": {
48
+ "@thymian/core-testing": "0.0.0-PLACEHOLDER"
49
+ }
50
+ }