flowlint 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/packages/config/flowlint-config.d.ts +64 -0
  2. package/dist/packages/config/flowlint-config.js +103 -0
  3. package/dist/packages/config/flowlint-config.js.map +1 -0
  4. package/dist/packages/config/index.d.ts +4 -0
  5. package/dist/packages/config/index.js +21 -0
  6. package/dist/packages/config/index.js.map +1 -0
  7. package/dist/packages/github/client.d.ts +2 -0
  8. package/dist/packages/github/client.js +94 -0
  9. package/dist/packages/github/client.js.map +1 -0
  10. package/dist/packages/logger/index.d.ts +11 -0
  11. package/dist/packages/logger/index.js +40 -0
  12. package/dist/packages/logger/index.js.map +1 -0
  13. package/dist/packages/observability/collectors.d.ts +40 -0
  14. package/dist/packages/observability/collectors.js +75 -0
  15. package/dist/packages/observability/collectors.js.map +1 -0
  16. package/dist/packages/observability/index.d.ts +10 -0
  17. package/dist/packages/observability/index.js +35 -0
  18. package/dist/packages/observability/index.js.map +1 -0
  19. package/dist/packages/observability/metrics.d.ts +119 -0
  20. package/dist/packages/observability/metrics.js +194 -0
  21. package/dist/packages/observability/metrics.js.map +1 -0
  22. package/dist/packages/observability/middleware.d.ts +32 -0
  23. package/dist/packages/observability/middleware.js +58 -0
  24. package/dist/packages/observability/middleware.js.map +1 -0
  25. package/dist/packages/review/analysis-engine.d.ts +19 -0
  26. package/dist/packages/review/analysis-engine.js +111 -0
  27. package/dist/packages/review/analysis-engine.js.map +1 -0
  28. package/dist/packages/review/index.d.ts +12 -0
  29. package/dist/packages/review/index.js +29 -0
  30. package/dist/packages/review/index.js.map +1 -0
  31. package/dist/packages/review/parser-n8n.d.ts +2 -0
  32. package/dist/packages/review/parser-n8n.js +118 -0
  33. package/dist/packages/review/parser-n8n.js.map +1 -0
  34. package/dist/packages/review/providers/github.d.ts +62 -0
  35. package/dist/packages/review/providers/github.js +275 -0
  36. package/dist/packages/review/providers/github.js.map +1 -0
  37. package/dist/packages/review/providers.d.ts +106 -0
  38. package/dist/packages/review/providers.js +12 -0
  39. package/dist/packages/review/providers.js.map +1 -0
  40. package/dist/packages/review/reporter.d.ts +17 -0
  41. package/dist/packages/review/reporter.js +62 -0
  42. package/dist/packages/review/reporter.js.map +1 -0
  43. package/dist/packages/review/rules/index.d.ts +9 -0
  44. package/dist/packages/review/rules/index.js +313 -0
  45. package/dist/packages/review/rules/index.js.map +1 -0
  46. package/dist/packages/review/rules/rule-utils.d.ts +36 -0
  47. package/dist/packages/review/rules/rule-utils.js +75 -0
  48. package/dist/packages/review/rules/rule-utils.js.map +1 -0
  49. package/dist/packages/review/schemas/index.d.ts +17 -0
  50. package/dist/packages/review/schemas/index.js +139 -0
  51. package/dist/packages/review/schemas/index.js.map +1 -0
  52. package/dist/packages/review/schemas/n8n-workflow.schema.json +177 -0
  53. package/dist/packages/review/sniffer.d.ts +15 -0
  54. package/dist/packages/review/sniffer.js +47 -0
  55. package/dist/packages/review/sniffer.js.map +1 -0
  56. package/dist/packages/review/types.d.ts +38 -0
  57. package/dist/packages/review/types.js +3 -0
  58. package/dist/packages/review/types.js.map +1 -0
  59. package/dist/packages/review/utils/findings.d.ts +23 -0
  60. package/dist/packages/review/utils/findings.js +34 -0
  61. package/dist/packages/review/utils/findings.js.map +1 -0
  62. package/dist/packages/review/utils/merge.d.ts +12 -0
  63. package/dist/packages/review/utils/merge.js +40 -0
  64. package/dist/packages/review/utils/merge.js.map +1 -0
  65. package/dist/packages/review/utils.d.ts +60 -0
  66. package/dist/packages/review/utils.js +214 -0
  67. package/dist/packages/review/utils.js.map +1 -0
  68. package/dist/packages/tracing/github-tracer.d.ts +38 -0
  69. package/dist/packages/tracing/github-tracer.js +79 -0
  70. package/dist/packages/tracing/github-tracer.js.map +1 -0
  71. package/dist/packages/tracing/index.d.ts +81 -0
  72. package/dist/packages/tracing/index.js +240 -0
  73. package/dist/packages/tracing/index.js.map +1 -0
  74. package/dist/packages/tracing/tracer.d.ts +30 -0
  75. package/dist/packages/tracing/tracer.js +141 -0
  76. package/dist/packages/tracing/tracer.js.map +1 -0
  77. package/package.json +10 -1
@@ -0,0 +1,177 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://flowlint.dev/schemas/n8n-workflow.json",
4
+ "title": "n8n Workflow Schema",
5
+ "description": "JSON Schema for n8n workflow files (v1.x)",
6
+ "type": "object",
7
+ "required": ["nodes", "connections"],
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "description": "Workflow name"
12
+ },
13
+ "nodes": {
14
+ "type": "array",
15
+ "description": "Array of workflow nodes",
16
+ "items": {
17
+ "type": "object",
18
+ "required": ["type", "name"],
19
+ "properties": {
20
+ "id": {
21
+ "type": "string",
22
+ "minLength": 1,
23
+ "description": "Unique node identifier"
24
+ },
25
+ "type": {
26
+ "type": "string",
27
+ "minLength": 1,
28
+ "description": "Node type (e.g., n8n-nodes-base.httpRequest)"
29
+ },
30
+ "name": {
31
+ "type": "string",
32
+ "minLength": 1,
33
+ "description": "Human-readable node name"
34
+ },
35
+ "parameters": {
36
+ "type": "object",
37
+ "description": "Node-specific configuration parameters"
38
+ },
39
+ "credentials": {
40
+ "type": "object",
41
+ "description": "Credential references for this node"
42
+ },
43
+ "position": {
44
+ "type": "array",
45
+ "description": "X,Y coordinates for UI placement",
46
+ "items": {
47
+ "type": "number"
48
+ },
49
+ "minItems": 2,
50
+ "maxItems": 2
51
+ },
52
+ "continueOnFail": {
53
+ "type": "boolean",
54
+ "description": "Whether to continue execution on node failure"
55
+ },
56
+ "disabled": {
57
+ "type": "boolean",
58
+ "description": "Whether the node is disabled"
59
+ },
60
+ "notesInFlow": {
61
+ "type": "boolean"
62
+ },
63
+ "notes": {
64
+ "type": "string"
65
+ },
66
+ "typeVersion": {
67
+ "type": "number",
68
+ "description": "Version of the node type"
69
+ }
70
+ },
71
+ "additionalProperties": true
72
+ }
73
+ },
74
+ "connections": {
75
+ "type": "object",
76
+ "description": "Map of node connections (source node ID -> connection details)",
77
+ "patternProperties": {
78
+ "^.*$": {
79
+ "type": "object",
80
+ "description": "Connection channels for a source node",
81
+ "patternProperties": {
82
+ "^(main|error|timeout|.*?)$": {
83
+ "description": "Connection array for this channel",
84
+ "oneOf": [
85
+ {
86
+ "type": "array",
87
+ "items": {
88
+ "type": "object",
89
+ "required": ["node"],
90
+ "properties": {
91
+ "node": {
92
+ "type": "string",
93
+ "description": "Target node ID or name"
94
+ },
95
+ "type": {
96
+ "type": "string",
97
+ "description": "Connection type"
98
+ },
99
+ "index": {
100
+ "type": "number",
101
+ "description": "Output index"
102
+ }
103
+ }
104
+ }
105
+ },
106
+ {
107
+ "type": "array",
108
+ "items": {
109
+ "type": "array",
110
+ "items": {
111
+ "type": "object",
112
+ "required": ["node"],
113
+ "properties": {
114
+ "node": {
115
+ "type": "string"
116
+ },
117
+ "type": {
118
+ "type": "string"
119
+ },
120
+ "index": {
121
+ "type": "number"
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ]
128
+ }
129
+ }
130
+ }
131
+ }
132
+ },
133
+ "active": {
134
+ "type": "boolean",
135
+ "description": "Whether the workflow is active"
136
+ },
137
+ "settings": {
138
+ "type": "object",
139
+ "description": "Workflow settings"
140
+ },
141
+ "tags": {
142
+ "type": "array",
143
+ "description": "Workflow tags",
144
+ "items": {
145
+ "oneOf": [
146
+ { "type": "string" },
147
+ {
148
+ "type": "object",
149
+ "required": ["name"],
150
+ "properties": {
151
+ "id": { "type": "string" },
152
+ "name": { "type": "string" }
153
+ },
154
+ "additionalProperties": true
155
+ }
156
+ ]
157
+ }
158
+ },
159
+ "pinData": {
160
+ "type": "object",
161
+ "description": "Pinned execution data for testing"
162
+ },
163
+ "versionId": {
164
+ "type": "string",
165
+ "description": "Workflow version identifier"
166
+ },
167
+ "id": {
168
+ "type": ["string", "number"],
169
+ "description": "Workflow ID"
170
+ },
171
+ "meta": {
172
+ "type": "object",
173
+ "description": "Metadata"
174
+ }
175
+ },
176
+ "additionalProperties": true
177
+ }
@@ -0,0 +1,15 @@
1
+ import type { Octokit } from 'octokit';
2
+ import type { PRFile } from './types';
3
+ export type GlobSet = {
4
+ include: string[];
5
+ ignore: string[];
6
+ };
7
+ export declare function pickTargets(files: PRFile[], globs: GlobSet): PRFile[];
8
+ export type FetchResult = {
9
+ contents: Map<string, string>;
10
+ errors: Array<{
11
+ filename: string;
12
+ error: string;
13
+ }>;
14
+ };
15
+ export declare function fetchRawFiles(gh: Octokit, repoFull: string, targets: PRFile[]): Promise<FetchResult>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pickTargets = pickTargets;
7
+ exports.fetchRawFiles = fetchRawFiles;
8
+ const logger_1 = require("../logger");
9
+ const micromatch_1 = __importDefault(require("micromatch"));
10
+ function pickTargets(files, globs) {
11
+ return files
12
+ .filter((file) => file.status !== 'removed')
13
+ .filter((file) => {
14
+ const normalized = file.filename.replace(/\\/g, '/');
15
+ const included = micromatch_1.default.isMatch(normalized, globs.include, { dot: true });
16
+ const ignored = micromatch_1.default.isMatch(normalized, globs.ignore, { dot: true });
17
+ return included && !ignored;
18
+ });
19
+ }
20
+ async function fetchRawFiles(gh, repoFull, targets) {
21
+ const [owner, repo] = repoFull.split('/');
22
+ const contents = new Map();
23
+ const errors = [];
24
+ for (const file of targets) {
25
+ if (!file.sha) {
26
+ errors.push({ filename: file.filename, error: 'Missing SHA (file may be removed)' });
27
+ continue;
28
+ }
29
+ try {
30
+ const { data: blob } = await gh.request('GET /repos/{owner}/{repo}/git/blobs/{file_sha}', {
31
+ owner,
32
+ repo,
33
+ file_sha: file.sha,
34
+ });
35
+ const raw = Buffer.from(blob.content, 'base64').toString('utf8');
36
+ contents.set(file.filename, raw);
37
+ }
38
+ catch (error) {
39
+ // Handle transient errors (404, timeouts, rate limits) gracefully
40
+ const errorMsg = error instanceof Error ? error.message : String(error);
41
+ logger_1.logger.warn({ filename: file.filename, error: errorMsg }, 'failed to fetch file');
42
+ errors.push({ filename: file.filename, error: errorMsg });
43
+ }
44
+ }
45
+ return { contents, errors };
46
+ }
47
+ //# sourceMappingURL=sniffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sniffer.js","sourceRoot":"","sources":["../../../packages/review/sniffer.ts"],"names":[],"mappings":";;;;;AAOA,kCASC;AAOD,sCAgCC;AArDD,sCAAmC;AACnC,4DAAoC;AAIpC,SAAgB,WAAW,CAAC,KAAe,EAAE,KAAc;IACzD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;SAC3C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,oBAAU,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,MAAM,OAAO,GAAG,oBAAU,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5E,OAAO,QAAQ,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC;AAOM,KAAK,UAAU,aAAa,CACjC,EAAW,EACX,QAAgB,EAChB,OAAiB;IAEjB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,MAAM,MAAM,GAA+C,EAAE,CAAC;IAE9D,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,gDAAgD,EAAE;gBACxF,KAAK;gBACL,IAAI;gBACJ,QAAQ,EAAE,IAAI,CAAC,GAAG;aACnB,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxE,eAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,sBAAsB,CAAC,CAAC;YAClF,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,38 @@
1
+ export type PRFile = {
2
+ filename: string;
3
+ status: string;
4
+ sha?: string;
5
+ patch?: string;
6
+ };
7
+ export type FindingSeverity = 'must' | 'should' | 'nit';
8
+ export type Finding = {
9
+ rule: string;
10
+ severity: FindingSeverity;
11
+ path: string;
12
+ message: string;
13
+ raw_details?: string;
14
+ nodeId?: string;
15
+ line?: number;
16
+ documentationUrl?: string;
17
+ };
18
+ export type NodeRef = {
19
+ id: string;
20
+ type: string;
21
+ name?: string;
22
+ params?: Record<string, unknown>;
23
+ cred?: Record<string, unknown>;
24
+ flags?: {
25
+ continueOnFail?: boolean;
26
+ retryOnFail?: boolean | string;
27
+ };
28
+ };
29
+ export type Edge = {
30
+ from: string;
31
+ to: string;
32
+ on?: 'success' | 'error' | 'timeout';
33
+ };
34
+ export type Graph = {
35
+ nodes: NodeRef[];
36
+ edges: Edge[];
37
+ meta: Record<string, unknown>;
38
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../packages/review/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Findings utilities
3
+ * Shared logic for processing and analyzing findings across both review engine and CLI
4
+ */
5
+ import type { Finding } from '../types';
6
+ export interface FindingsSummary {
7
+ must: number;
8
+ should: number;
9
+ nit: number;
10
+ total: number;
11
+ }
12
+ /**
13
+ * Count findings by severity level
14
+ */
15
+ export declare function countFindingsBySeverity(findings: Finding[]): FindingsSummary;
16
+ /**
17
+ * Get severity order for sorting
18
+ */
19
+ export declare function getSeverityOrder(): Record<string, number>;
20
+ /**
21
+ * Sort findings by severity
22
+ */
23
+ export declare function sortFindingsBySeverity(findings: Finding[]): Finding[];
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * Findings utilities
4
+ * Shared logic for processing and analyzing findings across both review engine and CLI
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.countFindingsBySeverity = countFindingsBySeverity;
8
+ exports.getSeverityOrder = getSeverityOrder;
9
+ exports.sortFindingsBySeverity = sortFindingsBySeverity;
10
+ /**
11
+ * Count findings by severity level
12
+ */
13
+ function countFindingsBySeverity(findings) {
14
+ return {
15
+ must: findings.filter((f) => f.severity === 'must').length,
16
+ should: findings.filter((f) => f.severity === 'should').length,
17
+ nit: findings.filter((f) => f.severity === 'nit').length,
18
+ total: findings.length,
19
+ };
20
+ }
21
+ /**
22
+ * Get severity order for sorting
23
+ */
24
+ function getSeverityOrder() {
25
+ return { must: 0, should: 1, nit: 2 };
26
+ }
27
+ /**
28
+ * Sort findings by severity
29
+ */
30
+ function sortFindingsBySeverity(findings) {
31
+ const order = getSeverityOrder();
32
+ return [...findings].sort((a, b) => order[a.severity] - order[b.severity]);
33
+ }
34
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../../../packages/review/utils/findings.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAcH,0DAOC;AAKD,4CAEC;AAKD,wDAGC;AAzBD;;GAEG;AACH,SAAgB,uBAAuB,CAAC,QAAmB;IACzD,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;QAC1D,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM;QAC9D,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM;QACxD,KAAK,EAAE,QAAQ,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB;IAC9B,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAgB,sBAAsB,CAAC,QAAmB;IACxD,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Deep merge utilities
3
+ * Shared logic for merging configuration objects
4
+ */
5
+ /**
6
+ * Deep merge configuration objects
7
+ */
8
+ export declare function deepMerge<T>(base: T, override: Record<string, unknown>): T;
9
+ /**
10
+ * Recursively merge source object into target object
11
+ */
12
+ export declare function mergeInto(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Deep merge utilities
4
+ * Shared logic for merging configuration objects
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.deepMerge = deepMerge;
8
+ exports.mergeInto = mergeInto;
9
+ /**
10
+ * Deep merge configuration objects
11
+ */
12
+ function deepMerge(base, override) {
13
+ const baseCopy = JSON.parse(JSON.stringify(base));
14
+ if (!override)
15
+ return baseCopy;
16
+ return mergeInto(baseCopy, override);
17
+ }
18
+ /**
19
+ * Recursively merge source object into target object
20
+ */
21
+ function mergeInto(target, source) {
22
+ for (const [key, value] of Object.entries(source)) {
23
+ if (value === undefined || value === null)
24
+ continue;
25
+ if (Array.isArray(value)) {
26
+ target[key] = value;
27
+ }
28
+ else if (typeof value === 'object') {
29
+ if (typeof target[key] !== 'object' || target[key] === null) {
30
+ target[key] = {};
31
+ }
32
+ mergeInto(target[key], value);
33
+ }
34
+ else {
35
+ target[key] = value;
36
+ }
37
+ }
38
+ return target;
39
+ }
40
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../packages/review/utils/merge.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAKH,8BAIC;AAKD,8BAeC;AA3BD;;GAEG;AACH,SAAgB,SAAS,CAAI,IAAO,EAAE,QAAiC;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,SAAS,CAAC,QAAe,EAAE,QAAQ,CAAM,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,SAAgB,SAAS,CAAC,MAA+B,EAAE,MAA+B;IACxF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QACpD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;YACnB,CAAC;YACD,SAAS,CAAC,MAAM,CAAC,GAAG,CAA4B,EAAE,KAAgC,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { Graph, NodeRef } from './types';
2
+ /**
3
+ * Shared utility functions for workflow parsing and validation
4
+ */
5
+ /**
6
+ * Helper to flatten nested connection arrays from n8n workflow connections.
7
+ * Connections can be nested in various ways (arrays of arrays, objects with node properties).
8
+ * This recursively flattens them to a simple array of connection objects.
9
+ *
10
+ * @param value - The connection value to flatten (can be array, object, or primitive)
11
+ * @returns Array of connection objects with 'node' property
12
+ */
13
+ export declare function flattenConnections(value: any): any[];
14
+ /**
15
+ * Build validation error objects from a collection of items using provided templates.
16
+ * This utility eliminates code duplication in validation error construction.
17
+ *
18
+ * @template T - Type of items to process
19
+ * @param items - Set or array of items to convert to validation errors
20
+ * @param errorConfig - Configuration object containing:
21
+ * - path: The JSON path where the error occurred
22
+ * - messageTemplate: Function to generate error message for each item
23
+ * - suggestionTemplate: Function to generate actionable suggestion for each item
24
+ * @returns Array of validation error objects with path, message, and suggestion fields
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const duplicates = new Set(['node1', 'node2']);
29
+ * const errors = buildValidationErrors(duplicates, {
30
+ * path: 'nodes[].id',
31
+ * messageTemplate: (id) => `Duplicate node ID: "${id}"`,
32
+ * suggestionTemplate: (id) => `Remove or rename the duplicate node with ID "${id}".`
33
+ * });
34
+ * ```
35
+ */
36
+ export declare function buildValidationErrors<T>(items: Set<T> | T[], errorConfig: {
37
+ path: string;
38
+ messageTemplate: (item: T) => string;
39
+ suggestionTemplate: (item: T) => string;
40
+ }): Array<{
41
+ path: string;
42
+ message: string;
43
+ suggestion: string;
44
+ }>;
45
+ export declare function collectStrings(value: unknown, out?: string[]): string[];
46
+ export declare function toRegex(pattern: string): RegExp;
47
+ export declare function isApiNode(type: string): boolean;
48
+ export declare function isMutationNode(type: string): boolean;
49
+ export declare function isErrorProneNode(type: string): boolean;
50
+ export declare function isNotificationNode(type: string): boolean;
51
+ export declare function isErrorHandlerNode(type: string, name?: string): boolean;
52
+ export declare function isRejoinNode(graph: Graph, nodeId: string): boolean;
53
+ export declare function isMeaningfulConsumer(node: NodeRef): boolean;
54
+ export declare function containsCandidate(value: unknown, candidates: string[]): boolean;
55
+ export declare function isTerminalNode(type: string, name?: string): boolean;
56
+ export declare function readNumber(source: any, paths: string[]): number | undefined;
57
+ export declare function findAllDownstreamNodes(graph: Graph, startNodeId: string): Set<string>;
58
+ export declare function findAllUpstreamNodes(graph: Graph, startNodeId: string): Set<string>;
59
+ export declare const EXAMPLES_BASE_URL = "https://github.com/Replikanti/flowlint/tree/main/flowlint-examples";
60
+ export declare function getExampleLink(ruleId: string): string;