flowlint 0.5.3 → 0.6.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.
Files changed (108) hide show
  1. package/README.md +45 -355
  2. package/dist/cli.js +163 -21
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +52 -57
  5. package/dist/cli.d.ts +0 -8
  6. package/dist/commands/init.d.ts +0 -8
  7. package/dist/commands/init.js +0 -34
  8. package/dist/commands/init.js.map +0 -1
  9. package/dist/commands/scan.d.ts +0 -11
  10. package/dist/commands/scan.js +0 -104
  11. package/dist/commands/scan.js.map +0 -1
  12. package/dist/packages/config/flowlint-config.d.ts +0 -73
  13. package/dist/packages/config/flowlint-config.js +0 -120
  14. package/dist/packages/config/flowlint-config.js.map +0 -1
  15. package/dist/packages/config/index.d.ts +0 -4
  16. package/dist/packages/config/index.js +0 -21
  17. package/dist/packages/config/index.js.map +0 -1
  18. package/dist/packages/github/client.d.ts +0 -2
  19. package/dist/packages/github/client.js +0 -94
  20. package/dist/packages/github/client.js.map +0 -1
  21. package/dist/packages/logger/index.d.ts +0 -11
  22. package/dist/packages/logger/index.js +0 -40
  23. package/dist/packages/logger/index.js.map +0 -1
  24. package/dist/packages/observability/collectors.d.ts +0 -40
  25. package/dist/packages/observability/collectors.js +0 -75
  26. package/dist/packages/observability/collectors.js.map +0 -1
  27. package/dist/packages/observability/index.d.ts +0 -10
  28. package/dist/packages/observability/index.js +0 -35
  29. package/dist/packages/observability/index.js.map +0 -1
  30. package/dist/packages/observability/metrics.d.ts +0 -119
  31. package/dist/packages/observability/metrics.js +0 -194
  32. package/dist/packages/observability/metrics.js.map +0 -1
  33. package/dist/packages/observability/middleware.d.ts +0 -32
  34. package/dist/packages/observability/middleware.js +0 -58
  35. package/dist/packages/observability/middleware.js.map +0 -1
  36. package/dist/packages/review/analysis-engine.d.ts +0 -19
  37. package/dist/packages/review/analysis-engine.js +0 -111
  38. package/dist/packages/review/analysis-engine.js.map +0 -1
  39. package/dist/packages/review/index.d.ts +0 -12
  40. package/dist/packages/review/index.js +0 -29
  41. package/dist/packages/review/index.js.map +0 -1
  42. package/dist/packages/review/parser-n8n.d.ts +0 -2
  43. package/dist/packages/review/parser-n8n.js +0 -122
  44. package/dist/packages/review/parser-n8n.js.map +0 -1
  45. package/dist/packages/review/providers/github.d.ts +0 -62
  46. package/dist/packages/review/providers/github.js +0 -275
  47. package/dist/packages/review/providers/github.js.map +0 -1
  48. package/dist/packages/review/providers.d.ts +0 -106
  49. package/dist/packages/review/providers.js +0 -12
  50. package/dist/packages/review/providers.js.map +0 -1
  51. package/dist/packages/review/reporter.d.ts +0 -17
  52. package/dist/packages/review/reporter.js +0 -59
  53. package/dist/packages/review/reporter.js.map +0 -1
  54. package/dist/packages/review/rules/index.d.ts +0 -9
  55. package/dist/packages/review/rules/index.js +0 -415
  56. package/dist/packages/review/rules/index.js.map +0 -1
  57. package/dist/packages/review/rules/rule-utils.d.ts +0 -36
  58. package/dist/packages/review/rules/rule-utils.js +0 -75
  59. package/dist/packages/review/rules/rule-utils.js.map +0 -1
  60. package/dist/packages/review/schemas/index.d.ts +0 -17
  61. package/dist/packages/review/schemas/index.js +0 -167
  62. package/dist/packages/review/schemas/index.js.map +0 -1
  63. package/dist/packages/review/schemas/n8n-workflow.schema.json +0 -177
  64. package/dist/packages/review/sniffer.d.ts +0 -15
  65. package/dist/packages/review/sniffer.js +0 -47
  66. package/dist/packages/review/sniffer.js.map +0 -1
  67. package/dist/packages/review/types.d.ts +0 -40
  68. package/dist/packages/review/types.js +0 -3
  69. package/dist/packages/review/types.js.map +0 -1
  70. package/dist/packages/review/utils/findings.d.ts +0 -23
  71. package/dist/packages/review/utils/findings.js +0 -34
  72. package/dist/packages/review/utils/findings.js.map +0 -1
  73. package/dist/packages/review/utils/merge.d.ts +0 -12
  74. package/dist/packages/review/utils/merge.js +0 -40
  75. package/dist/packages/review/utils/merge.js.map +0 -1
  76. package/dist/packages/review/utils.d.ts +0 -60
  77. package/dist/packages/review/utils.js +0 -214
  78. package/dist/packages/review/utils.js.map +0 -1
  79. package/dist/packages/tracing/github-tracer.d.ts +0 -38
  80. package/dist/packages/tracing/github-tracer.js +0 -79
  81. package/dist/packages/tracing/github-tracer.js.map +0 -1
  82. package/dist/packages/tracing/index.d.ts +0 -81
  83. package/dist/packages/tracing/index.js +0 -240
  84. package/dist/packages/tracing/index.js.map +0 -1
  85. package/dist/packages/tracing/tracer.d.ts +0 -30
  86. package/dist/packages/tracing/tracer.js +0 -141
  87. package/dist/packages/tracing/tracer.js.map +0 -1
  88. package/dist/providers/local-config-provider.d.ts +0 -11
  89. package/dist/providers/local-config-provider.js +0 -39
  90. package/dist/providers/local-config-provider.js.map +0 -1
  91. package/dist/providers/local-file-source.d.ts +0 -13
  92. package/dist/providers/local-file-source.js +0 -47
  93. package/dist/providers/local-file-source.js.map +0 -1
  94. package/dist/reporters/console-reporter.d.ts +0 -8
  95. package/dist/reporters/console-reporter.js +0 -75
  96. package/dist/reporters/console-reporter.js.map +0 -1
  97. package/dist/reporters/github-actions-reporter.d.ts +0 -30
  98. package/dist/reporters/github-actions-reporter.js +0 -104
  99. package/dist/reporters/github-actions-reporter.js.map +0 -1
  100. package/dist/reporters/json-reporter.d.ts +0 -14
  101. package/dist/reporters/json-reporter.js +0 -57
  102. package/dist/reporters/json-reporter.js.map +0 -1
  103. package/dist/reporters/junit-reporter.d.ts +0 -25
  104. package/dist/reporters/junit-reporter.js +0 -142
  105. package/dist/reporters/junit-reporter.js.map +0 -1
  106. package/dist/reporters/sarif-reporter.d.ts +0 -21
  107. package/dist/reporters/sarif-reporter.js +0 -125
  108. package/dist/reporters/sarif-reporter.js.map +0 -1
@@ -1,36 +0,0 @@
1
- import type { Graph, Finding, NodeRef, FindingSeverity } from '../types';
2
- import type { FlowLintConfig } from '../../config/flowlint-config';
3
- type Rule = string;
4
- type RuleContext = {
5
- path: string;
6
- cfg: FlowLintConfig;
7
- nodeLines?: Record<string, number>;
8
- };
9
- type RuleRunner = (graph: Graph, ctx: RuleContext) => Finding[];
10
- type NodeRuleLogic = (node: NodeRef, graph: Graph, ctx: RuleContext) => Finding | Finding[] | null;
11
- /**
12
- * A higher-order function to create a rule that iterates over each node in the graph.
13
- * It abstracts the boilerplate of checking if the rule is enabled and iterating through nodes.
14
- *
15
- * @param ruleId - The ID of the rule (e.g., 'R1').
16
- * @param configKey - The key in the FlowLintConfig rules object.
17
- * @param logic - The function containing the core logic to be executed for each node.
18
- * @returns A RuleRunner function.
19
- */
20
- export declare function createNodeRule(ruleId: Rule, configKey: keyof FlowLintConfig['rules'], logic: NodeRuleLogic): RuleRunner;
21
- type HardcodedStringRuleOptions = {
22
- ruleId: Rule;
23
- severity: FindingSeverity;
24
- configKey: 'secrets' | 'config_literals';
25
- messageFn: (node: NodeRef, value: string) => string;
26
- details: string;
27
- };
28
- /**
29
- * Creates a rule that checks for hardcoded strings in node parameters based on a denylist of regex patterns.
30
- * This is used to create R4 (Secrets) and R9 (Config Literals).
31
- *
32
- * @param options - The configuration for the hardcoded string rule.
33
- * @returns A RuleRunner function.
34
- */
35
- export declare function createHardcodedStringRule({ ruleId, severity, configKey, messageFn, details, }: HardcodedStringRuleOptions): RuleRunner;
36
- export {};
@@ -1,75 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createNodeRule = createNodeRule;
4
- exports.createHardcodedStringRule = createHardcodedStringRule;
5
- const utils_1 = require("../utils");
6
- /**
7
- * A higher-order function to create a rule that iterates over each node in the graph.
8
- * It abstracts the boilerplate of checking if the rule is enabled and iterating through nodes.
9
- *
10
- * @param ruleId - The ID of the rule (e.g., 'R1').
11
- * @param configKey - The key in the FlowLintConfig rules object.
12
- * @param logic - The function containing the core logic to be executed for each node.
13
- * @returns A RuleRunner function.
14
- */
15
- function createNodeRule(ruleId, configKey, logic) {
16
- return (graph, ctx) => {
17
- const ruleConfig = ctx.cfg.rules[configKey];
18
- if (!ruleConfig?.enabled) {
19
- return [];
20
- }
21
- const findings = [];
22
- for (const node of graph.nodes) {
23
- const result = logic(node, graph, ctx);
24
- if (result) {
25
- if (Array.isArray(result)) {
26
- findings.push(...result);
27
- }
28
- else {
29
- findings.push(result);
30
- }
31
- }
32
- }
33
- return findings;
34
- };
35
- }
36
- /**
37
- * Creates a rule that checks for hardcoded strings in node parameters based on a denylist of regex patterns.
38
- * This is used to create R4 (Secrets) and R9 (Config Literals).
39
- *
40
- * @param options - The configuration for the hardcoded string rule.
41
- * @returns A RuleRunner function.
42
- */
43
- function createHardcodedStringRule({ ruleId, severity, configKey, messageFn, details, }) {
44
- const logic = (node, graph, ctx) => {
45
- const cfg = ctx.cfg.rules[configKey];
46
- if (!cfg.denylist_regex?.length) {
47
- return null;
48
- }
49
- const regexes = cfg.denylist_regex.map((pattern) => (0, utils_1.toRegex)(pattern));
50
- const findings = [];
51
- const strings = (0, utils_1.collectStrings)(node.params);
52
- for (const value of strings) {
53
- // Ignore expressions and empty strings
54
- if (!value || value.includes('{{')) {
55
- continue;
56
- }
57
- if (regexes.some((regex) => regex.test(value))) {
58
- findings.push({
59
- rule: ruleId,
60
- severity,
61
- path: ctx.path,
62
- message: messageFn(node, value),
63
- nodeId: node.id,
64
- line: ctx.nodeLines?.[node.id],
65
- raw_details: details,
66
- });
67
- // Only report one finding per node to avoid noise
68
- break;
69
- }
70
- }
71
- return findings;
72
- };
73
- return createNodeRule(ruleId, configKey, logic);
74
- }
75
- //# sourceMappingURL=rule-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rule-utils.js","sourceRoot":"","sources":["../../../../packages/review/rules/rule-utils.ts"],"names":[],"mappings":";;AAkBA,wCAwBC;AAiBD,8DAyCC;AAlGD,oCAAmD;AAOnD;;;;;;;;GAQG;AACH,SAAgB,cAAc,CAC5B,MAAY,EACZ,SAAwC,EACxC,KAAoB;IAEpB,OAAO,CAAC,KAAY,EAAE,GAAgB,EAAa,EAAE;QACnD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAA0B,CAAC;QACrE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YACvC,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1B,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC3B,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC;AAUD;;;;;;GAMG;AACH,SAAgB,yBAAyB,CAAC,EACxC,MAAM,EACN,QAAQ,EACR,SAAS,EACT,SAAS,EACT,OAAO,GACoB;IAC3B,MAAM,KAAK,GAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAA,eAAO,EAAC,OAAO,CAAC,CAAC,CAAC;QAEtE,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,IAAA,sBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,uCAAuC;YACvC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,SAAS;YACX,CAAC;YAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC/C,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,MAAM;oBACZ,QAAQ;oBACR,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC;oBAC/B,MAAM,EAAE,IAAI,CAAC,EAAE;oBACf,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9B,WAAW,EAAE,OAAO;iBACrB,CAAC,CAAC;gBACH,kDAAkD;gBAClD,MAAM;YACR,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAClD,CAAC"}
@@ -1,17 +0,0 @@
1
- export declare class ValidationError extends Error {
2
- errors: Array<{
3
- path: string;
4
- message: string;
5
- suggestion?: string;
6
- }>;
7
- constructor(errors: Array<{
8
- path: string;
9
- message: string;
10
- suggestion?: string;
11
- }>);
12
- }
13
- /**
14
- * Validate n8n workflow structure
15
- * Throws ValidationError with detailed messages if validation fails
16
- */
17
- export declare function validateN8nWorkflow(data: any): void;
@@ -1,167 +0,0 @@
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.ValidationError = void 0;
7
- exports.validateN8nWorkflow = validateN8nWorkflow;
8
- const ajv_1 = __importDefault(require("ajv"));
9
- const ajv_formats_1 = __importDefault(require("ajv-formats"));
10
- const n8n_workflow_schema_json_1 = __importDefault(require("./n8n-workflow.schema.json"));
11
- const utils_1 = require("../utils");
12
- // Custom error class for validation failures
13
- class ValidationError extends Error {
14
- constructor(errors) {
15
- super(`Workflow validation failed: ${errors.length} error(s)`);
16
- this.errors = errors;
17
- this.name = 'ValidationError';
18
- }
19
- }
20
- exports.ValidationError = ValidationError;
21
- // Dummy validator that always passes
22
- const createDummyValidator = () => {
23
- const v = () => true;
24
- v.errors = [];
25
- return v;
26
- };
27
- // Singleton instance
28
- let validatorInstance = null;
29
- function getValidator() {
30
- if (validatorInstance)
31
- return validatorInstance;
32
- // Detect Node.js environment safely
33
- // Use optional chaining to satisfy SonarQube
34
- const isNode = typeof process !== 'undefined' && process?.versions?.node != null;
35
- if (isNode) {
36
- try {
37
- const ajv = new ajv_1.default({
38
- allErrors: true,
39
- strict: false,
40
- verbose: true,
41
- code: { source: true, es5: true }
42
- });
43
- (0, ajv_formats_1.default)(ajv);
44
- validatorInstance = ajv.compile(n8n_workflow_schema_json_1.default);
45
- }
46
- catch (error) {
47
- // Fallback to dummy validator if compilation fails (e.g. due to strict CSP in some environments)
48
- console.warn('Failed to compile JSON schema validator, falling back to dummy validator:', error);
49
- validatorInstance = createDummyValidator();
50
- }
51
- }
52
- else {
53
- validatorInstance = createDummyValidator();
54
- }
55
- return validatorInstance;
56
- }
57
- /**
58
- * Throws a ValidationError if the provided set contains items.
59
- * Centralizes the pattern of checking validation results and throwing errors.
60
- *
61
- * @param items - Set of items that represent validation failures
62
- * @param config - Configuration for building error messages
63
- * @throws ValidationError if items set is not empty
64
- */
65
- function throwIfInvalid(items, config) {
66
- if (items.size > 0) {
67
- const errors = (0, utils_1.buildValidationErrors)(items, config);
68
- throw new ValidationError(errors);
69
- }
70
- }
71
- /**
72
- * Check for duplicate node IDs in the workflow
73
- */
74
- function checkDuplicateNodeIds(data) {
75
- if (!Array.isArray(data.nodes))
76
- return;
77
- const seen = new Set();
78
- const duplicates = new Set();
79
- for (const node of data.nodes) {
80
- if (node.id && seen.has(node.id)) {
81
- duplicates.add(node.id);
82
- }
83
- if (node.id) {
84
- seen.add(node.id);
85
- }
86
- }
87
- throwIfInvalid(duplicates, {
88
- path: 'nodes[].id',
89
- messageTemplate: (id) => `Duplicate node ID: "${id}"`,
90
- suggestionTemplate: (id) => `Each node must have a unique ID. Remove or rename the duplicate node with ID "${id}".`,
91
- });
92
- }
93
- /**
94
- * Check for orphaned connections (references to non-existent nodes)
95
- */
96
- function checkOrphanedConnections(data) {
97
- if (!data.connections || !Array.isArray(data.nodes))
98
- return;
99
- const nodeIds = new Set();
100
- const nodeNames = new Set();
101
- // Collect all node IDs and names
102
- for (const node of data.nodes) {
103
- if (node.id)
104
- nodeIds.add(node.id);
105
- if (node.name)
106
- nodeNames.add(node.name);
107
- }
108
- const orphanedRefs = new Set();
109
- // Check all connection targets
110
- Object.entries(data.connections).forEach(([sourceId, channels]) => {
111
- // Check if source exists
112
- if (!nodeIds.has(sourceId) && !nodeNames.has(sourceId)) {
113
- orphanedRefs.add(sourceId);
114
- }
115
- // Check targets
116
- if (typeof channels === 'object' && channels !== null) {
117
- Object.values(channels).forEach((connArray) => {
118
- const flatConnections = (0, utils_1.flattenConnections)(connArray);
119
- flatConnections.forEach((conn) => {
120
- if (conn?.node) {
121
- if (!nodeIds.has(conn.node) && !nodeNames.has(conn.node)) {
122
- orphanedRefs.add(conn.node);
123
- }
124
- }
125
- });
126
- });
127
- }
128
- });
129
- throwIfInvalid(orphanedRefs, {
130
- path: 'connections',
131
- messageTemplate: (ref) => `Orphaned connection reference: "${ref}"`,
132
- suggestionTemplate: (ref) => `Connection references node "${ref}" which does not exist. Add the missing node or remove the invalid connection.`,
133
- });
134
- }
135
- /**
136
- * Validate n8n workflow structure
137
- * Throws ValidationError with detailed messages if validation fails
138
- */
139
- function validateN8nWorkflow(data) {
140
- const validate = getValidator();
141
- // Basic schema validation
142
- if (!validate(data)) {
143
- const errors = (validate.errors || []).map((err) => {
144
- const path = err.instancePath || err.schemaPath;
145
- const message = err.message || 'Validation error';
146
- let suggestion = '';
147
- // Provide helpful suggestions based on error type
148
- if (err.keyword === 'required') {
149
- const missing = err.params?.missingProperty;
150
- suggestion = `Add the required field "${missing}" to the workflow.`;
151
- }
152
- else if (err.keyword === 'type') {
153
- const expected = err.params?.type;
154
- suggestion = `The field should be of type "${expected}".`;
155
- }
156
- else if (err.keyword === 'minLength') {
157
- suggestion = 'This field cannot be empty.';
158
- }
159
- return { path, message, suggestion };
160
- });
161
- throw new ValidationError(errors);
162
- }
163
- // Additional custom validations
164
- checkDuplicateNodeIds(data);
165
- checkOrphanedConnections(data);
166
- }
167
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/review/schemas/index.ts"],"names":[],"mappings":"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"}
@@ -1,177 +0,0 @@
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
- }
@@ -1,15 +0,0 @@
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>;
@@ -1,47 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,40 +0,0 @@
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
- waitBetweenTries?: number | string;
28
- maxTries?: number | string;
29
- };
30
- };
31
- export type Edge = {
32
- from: string;
33
- to: string;
34
- on?: 'success' | 'error' | 'timeout';
35
- };
36
- export type Graph = {
37
- nodes: NodeRef[];
38
- edges: Edge[];
39
- meta: Record<string, unknown>;
40
- };
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../packages/review/types.ts"],"names":[],"mappings":""}
@@ -1,23 +0,0 @@
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[];
@@ -1,34 +0,0 @@
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