@synergenius/flow-weaver 0.13.2 → 0.14.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 +41 -2
- package/dist/api/validate.js +8 -2
- package/dist/ast/types.d.ts +120 -0
- package/dist/chevrotain-parser/node-parser.d.ts +4 -0
- package/dist/chevrotain-parser/node-parser.js +41 -1
- package/dist/chevrotain-parser/port-parser.d.ts +1 -0
- package/dist/chevrotain-parser/port-parser.js +22 -2
- package/dist/chevrotain-parser/tokens.d.ts +3 -0
- package/dist/chevrotain-parser/tokens.js +15 -0
- package/dist/cli/commands/export.js +25 -38
- package/dist/cli/flow-weaver.mjs +63703 -54297
- package/dist/cli/templates/index.js +9 -0
- package/dist/cli/templates/workflows/cicd-docker.d.ts +9 -0
- package/dist/cli/templates/workflows/cicd-docker.js +110 -0
- package/dist/cli/templates/workflows/cicd-matrix.d.ts +9 -0
- package/dist/cli/templates/workflows/cicd-matrix.js +112 -0
- package/dist/cli/templates/workflows/cicd-multi-env.d.ts +9 -0
- package/dist/cli/templates/workflows/cicd-multi-env.js +118 -0
- package/dist/cli/templates/workflows/cicd-test-deploy.d.ts +11 -0
- package/dist/cli/templates/workflows/cicd-test-deploy.js +149 -0
- package/dist/constants.js +7 -0
- package/dist/deployment/index.d.ts +14 -7
- package/dist/deployment/index.js +29 -17
- package/dist/deployment/targets/base.d.ts +27 -2
- package/dist/deployment/targets/base.js +38 -6
- package/dist/deployment/targets/cicd-base.d.ts +111 -0
- package/dist/deployment/targets/cicd-base.js +357 -0
- package/dist/deployment/targets/cloudflare.d.ts +6 -0
- package/dist/deployment/targets/cloudflare.js +3 -0
- package/dist/deployment/targets/github-actions.d.ts +54 -0
- package/dist/deployment/targets/github-actions.js +366 -0
- package/dist/deployment/targets/gitlab-ci.d.ts +65 -0
- package/dist/deployment/targets/gitlab-ci.js +374 -0
- package/dist/deployment/targets/inngest.d.ts +25 -0
- package/dist/deployment/targets/inngest.js +10 -1
- package/dist/deployment/targets/lambda.d.ts +17 -0
- package/dist/deployment/targets/lambda.js +5 -0
- package/dist/deployment/targets/vercel.d.ts +16 -0
- package/dist/deployment/targets/vercel.js +5 -0
- package/dist/diagram/geometry.js +13 -5
- package/dist/export/index.d.ts +13 -9
- package/dist/export/index.js +129 -997
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/jsdoc-parser.d.ts +130 -0
- package/dist/jsdoc-parser.js +408 -4
- package/dist/marketplace/index.d.ts +1 -1
- package/dist/marketplace/types.d.ts +13 -0
- package/dist/marketplace/validator.js +21 -2
- package/dist/mcp/tools-export.js +56 -14
- package/dist/parser.js +28 -1
- package/dist/validation/cicd-detection.d.ts +33 -0
- package/dist/validation/cicd-detection.js +76 -0
- package/dist/validation/cicd-rules.d.ts +62 -0
- package/dist/validation/cicd-rules.js +284 -0
- package/docs/reference/scaffold.md +4 -0
- package/package.json +4 -3
|
@@ -26,6 +26,8 @@ export type TMarketplaceManifest = {
|
|
|
26
26
|
workflows: TManifestWorkflow[];
|
|
27
27
|
/** Patterns included in this package */
|
|
28
28
|
patterns: TManifestPattern[];
|
|
29
|
+
/** Export targets provided by this package */
|
|
30
|
+
exportTargets?: TManifestExportTarget[];
|
|
29
31
|
/** External dependency information */
|
|
30
32
|
dependencies?: {
|
|
31
33
|
/** Flow Weaver peer dependency constraints */
|
|
@@ -34,6 +36,17 @@ export type TMarketplaceManifest = {
|
|
|
34
36
|
npm?: Record<string, string>;
|
|
35
37
|
};
|
|
36
38
|
};
|
|
39
|
+
/** An export target provided by a marketplace package. */
|
|
40
|
+
export type TManifestExportTarget = {
|
|
41
|
+
/** Target identifier (e.g. "lambda", "azure-pipelines") */
|
|
42
|
+
name: string;
|
|
43
|
+
/** Human-readable description */
|
|
44
|
+
description?: string;
|
|
45
|
+
/** Relative path to the compiled JS file that exports the target class */
|
|
46
|
+
file: string;
|
|
47
|
+
/** Named export from the file (default: "default") */
|
|
48
|
+
exportName?: string;
|
|
49
|
+
};
|
|
37
50
|
export type TManifestPort = {
|
|
38
51
|
dataType: TDataType;
|
|
39
52
|
description?: string;
|
|
@@ -47,10 +47,29 @@ function validatePackageJson(pkg, directory) {
|
|
|
47
47
|
// ── Manifest-level rules ─────────────────────────────────────────────────────
|
|
48
48
|
function validateManifestContents(manifest) {
|
|
49
49
|
const issues = [];
|
|
50
|
-
const totalUnits = manifest.nodeTypes.length + manifest.workflows.length + manifest.patterns.length
|
|
50
|
+
const totalUnits = manifest.nodeTypes.length + manifest.workflows.length + manifest.patterns.length +
|
|
51
|
+
(manifest.exportTargets?.length ?? 0);
|
|
51
52
|
// PKG-006: Must contain at least one unit
|
|
52
53
|
if (totalUnits === 0) {
|
|
53
|
-
issues.push(issue('PKG-006', 'error', 'Package must contain at least one node type, workflow, or
|
|
54
|
+
issues.push(issue('PKG-006', 'error', 'Package must contain at least one node type, workflow, pattern, or export target'));
|
|
55
|
+
}
|
|
56
|
+
// TGT-001: Export target entries must have name and file
|
|
57
|
+
for (const et of manifest.exportTargets ?? []) {
|
|
58
|
+
if (!et.name) {
|
|
59
|
+
issues.push(issue('TGT-001', 'error', 'Export target entry must have a "name"'));
|
|
60
|
+
}
|
|
61
|
+
if (!et.file) {
|
|
62
|
+
issues.push(issue('TGT-001', 'error', `Export target "${et.name || '(unnamed)'}" must have a "file"`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// TGT-002: Export target names must be unique within the package
|
|
66
|
+
const etNames = new Set();
|
|
67
|
+
for (const et of manifest.exportTargets ?? []) {
|
|
68
|
+
if (et.name && etNames.has(et.name)) {
|
|
69
|
+
issues.push(issue('TGT-002', 'error', `Duplicate export target name: "${et.name}"`));
|
|
70
|
+
}
|
|
71
|
+
if (et.name)
|
|
72
|
+
etNames.add(et.name);
|
|
54
73
|
}
|
|
55
74
|
// UNIT-002: Node type names must be unique within the package
|
|
56
75
|
const ntNames = new Set();
|
package/dist/mcp/tools-export.js
CHANGED
|
@@ -14,8 +14,8 @@ export function registerExportTools(mcp) {
|
|
|
14
14
|
mcp.tool('fw_export', 'Export workflows as serverless deployments. Generates handler code, platform config, and deploy instructions.', {
|
|
15
15
|
filePath: z.string().describe('Path to the workflow .ts file'),
|
|
16
16
|
target: z
|
|
17
|
-
.
|
|
18
|
-
.describe('Deployment target platform'),
|
|
17
|
+
.string()
|
|
18
|
+
.describe('Deployment target platform (e.g. lambda, vercel, cloudflare, inngest, github-actions, gitlab-ci). Run with --list-targets to see installed targets.'),
|
|
19
19
|
outputDir: z.string().describe('Output directory for generated files'),
|
|
20
20
|
serviceName: z
|
|
21
21
|
.string()
|
|
@@ -54,7 +54,16 @@ export function registerExportTools(mcp) {
|
|
|
54
54
|
catch {
|
|
55
55
|
return makeErrorResult('FILE_NOT_FOUND', `File not found: ${filePath}`);
|
|
56
56
|
}
|
|
57
|
-
// 2.
|
|
57
|
+
// 2. Discover targets from installed packs
|
|
58
|
+
const registry = await createTargetRegistry(process.cwd());
|
|
59
|
+
const exportTarget = registry.get(args.target);
|
|
60
|
+
if (!exportTarget) {
|
|
61
|
+
const available = registry.getNames();
|
|
62
|
+
return makeErrorResult('INVALID_TARGET', available.length === 0
|
|
63
|
+
? `No export targets installed. Install a target pack (e.g. npm install flowweaver-pack-${args.target})`
|
|
64
|
+
: `Unknown target: "${args.target}". Installed: ${available.join(', ')}`);
|
|
65
|
+
}
|
|
66
|
+
// 3. Parse the file to discover workflows and node types
|
|
58
67
|
let parseResult;
|
|
59
68
|
try {
|
|
60
69
|
parseResult = await parseWorkflow(filePath, { nodeTypesOnly: false });
|
|
@@ -77,21 +86,50 @@ export function registerExportTools(mcp) {
|
|
|
77
86
|
return makeErrorResult('PARSE_ERROR', `Parse errors in ${filePath}: ${parseResult.errors.join('; ')}`);
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
|
-
//
|
|
81
|
-
const registry = createTargetRegistry();
|
|
82
|
-
const exportTarget = registry.get(args.target);
|
|
83
|
-
if (!exportTarget) {
|
|
84
|
-
return makeErrorResult('INVALID_TARGET', `Unknown target: ${args.target}. Supported: lambda, vercel, cloudflare, inngest`);
|
|
85
|
-
}
|
|
89
|
+
// CI/CD targets use generate() directly — they read the AST, not compiled code
|
|
86
90
|
if (!exportTarget.generateBundle) {
|
|
87
|
-
|
|
91
|
+
const serviceName = args.serviceName || path.basename(filePath, '.ts').replace(/[^a-zA-Z0-9-]/g, '-');
|
|
92
|
+
const artifacts = await exportTarget.generate({
|
|
93
|
+
sourceFile: filePath,
|
|
94
|
+
workflowName: args.workflows?.[0] || serviceName,
|
|
95
|
+
displayName: serviceName,
|
|
96
|
+
outputDir,
|
|
97
|
+
production: true,
|
|
98
|
+
});
|
|
99
|
+
// Write files if not preview
|
|
100
|
+
if (!preview) {
|
|
101
|
+
await fs.promises.mkdir(outputDir, { recursive: true });
|
|
102
|
+
for (const file of artifacts.files) {
|
|
103
|
+
const fullPath = path.join(outputDir, file.relativePath);
|
|
104
|
+
await fs.promises.mkdir(path.dirname(fullPath), { recursive: true });
|
|
105
|
+
await fs.promises.writeFile(fullPath, file.content, 'utf-8');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const instructions = exportTarget.getDeployInstructions(artifacts);
|
|
109
|
+
return makeToolResult({
|
|
110
|
+
preview,
|
|
111
|
+
target: args.target,
|
|
112
|
+
serviceName,
|
|
113
|
+
outputDir,
|
|
114
|
+
files: artifacts.files.map((f) => ({
|
|
115
|
+
path: f.relativePath,
|
|
116
|
+
type: f.type,
|
|
117
|
+
size: f.content.length,
|
|
118
|
+
})),
|
|
119
|
+
instructions: {
|
|
120
|
+
title: instructions.title,
|
|
121
|
+
steps: instructions.steps,
|
|
122
|
+
prerequisites: instructions.prerequisites,
|
|
123
|
+
},
|
|
124
|
+
summary: preview
|
|
125
|
+
? `Preview: ${artifacts.files.length} files would be generated in ${outputDir}`
|
|
126
|
+
: `Exported ${artifacts.files.length} files to ${outputDir}`,
|
|
127
|
+
});
|
|
88
128
|
}
|
|
89
129
|
// 4. Build workflow and node type lists
|
|
90
|
-
// parseResult.allWorkflows has all TWorkflowAST[] from the file;
|
|
91
|
-
// each workflow's nodeTypes are in workflow.nodeTypes (TNodeTypeAST[])
|
|
92
130
|
const allWorkflows = parseResult.allWorkflows || [];
|
|
93
131
|
const allNodeTypes = allWorkflows.flatMap((w) => w.nodeTypes || []);
|
|
94
|
-
// Deduplicate node types by name
|
|
132
|
+
// Deduplicate node types by name
|
|
95
133
|
const uniqueNodeTypes = [
|
|
96
134
|
...new Map(allNodeTypes.map((nt) => [nt.name, nt])).values(),
|
|
97
135
|
];
|
|
@@ -133,7 +171,11 @@ export function registerExportTools(mcp) {
|
|
|
133
171
|
outputDir,
|
|
134
172
|
production: true,
|
|
135
173
|
includeDocs,
|
|
136
|
-
targetOptions:
|
|
174
|
+
targetOptions: {
|
|
175
|
+
...(args.durableSteps && { durableSteps: true }),
|
|
176
|
+
// Pass @deploy config from workflow AST so targets can read their annotations
|
|
177
|
+
...(allWorkflows[0]?.options?.deploy && { deploy: allWorkflows[0].options.deploy }),
|
|
178
|
+
},
|
|
137
179
|
});
|
|
138
180
|
// 6. Write files if not preview
|
|
139
181
|
if (!preview) {
|
package/dist/parser.js
CHANGED
|
@@ -612,6 +612,7 @@ export class AnnotationParser {
|
|
|
612
612
|
label: portDef.label,
|
|
613
613
|
expression: portDef.expression,
|
|
614
614
|
...(portDef.scope && { scope: portDef.scope }),
|
|
615
|
+
...(portDef.hidden && { hidden: portDef.hidden }),
|
|
615
616
|
...(portDef.metadata && { metadata: portDef.metadata }),
|
|
616
617
|
...(portDef.tsType && { tsType: portDef.tsType }),
|
|
617
618
|
};
|
|
@@ -624,6 +625,7 @@ export class AnnotationParser {
|
|
|
624
625
|
dataType: portDef.type,
|
|
625
626
|
label: portDef.label,
|
|
626
627
|
...(portDef.scope && { scope: portDef.scope }),
|
|
628
|
+
...(portDef.hidden && { hidden: portDef.hidden }),
|
|
627
629
|
...(portDef.metadata && { metadata: portDef.metadata }),
|
|
628
630
|
...(portDef.tsType && { tsType: portDef.tsType }),
|
|
629
631
|
};
|
|
@@ -745,6 +747,7 @@ export class AnnotationParser {
|
|
|
745
747
|
tags: config.tags,
|
|
746
748
|
}
|
|
747
749
|
: undefined,
|
|
750
|
+
...(config.deploy && { deploy: config.deploy }),
|
|
748
751
|
sourceLocation: {
|
|
749
752
|
file: sourceFile.getFilePath(),
|
|
750
753
|
line: fn.getStartLineNumber(false),
|
|
@@ -896,6 +899,8 @@ export class AnnotationParser {
|
|
|
896
899
|
...(inst.sourceLocation && {
|
|
897
900
|
sourceLocation: { file: filePath, ...inst.sourceLocation },
|
|
898
901
|
}),
|
|
902
|
+
...(inst.job && { job: inst.job }),
|
|
903
|
+
...(inst.environment && { environment: inst.environment }),
|
|
899
904
|
};
|
|
900
905
|
});
|
|
901
906
|
// Convert connections to ConnectionAST
|
|
@@ -985,7 +990,11 @@ export class AnnotationParser {
|
|
|
985
990
|
...(Object.keys(ui).length > 0 && { ui }),
|
|
986
991
|
...((config.strictTypes !== undefined || config.autoConnect ||
|
|
987
992
|
config.trigger || config.cancelOn || config.retries !== undefined ||
|
|
988
|
-
config.timeout || config.throttle
|
|
993
|
+
config.timeout || config.throttle ||
|
|
994
|
+
config.secrets || config.runner || config.caches || config.artifacts ||
|
|
995
|
+
config.environments || config.matrix || config.services ||
|
|
996
|
+
config.concurrency || config.cicdTriggers ||
|
|
997
|
+
config.deploy) && {
|
|
989
998
|
options: {
|
|
990
999
|
...(config.strictTypes !== undefined && { strictTypes: config.strictTypes }),
|
|
991
1000
|
...(config.autoConnect && { autoConnect: true }),
|
|
@@ -994,6 +1003,24 @@ export class AnnotationParser {
|
|
|
994
1003
|
...(config.retries !== undefined && { retries: config.retries }),
|
|
995
1004
|
...(config.timeout && { timeout: config.timeout }),
|
|
996
1005
|
...(config.throttle && { throttle: config.throttle }),
|
|
1006
|
+
// CI/CD domain options (grouped)
|
|
1007
|
+
...((config.secrets || config.runner || config.caches || config.artifacts ||
|
|
1008
|
+
config.environments || config.matrix || config.services ||
|
|
1009
|
+
config.concurrency || config.cicdTriggers) && {
|
|
1010
|
+
cicd: {
|
|
1011
|
+
...(config.secrets && { secrets: config.secrets }),
|
|
1012
|
+
...(config.runner && { runner: config.runner }),
|
|
1013
|
+
...(config.caches && { caches: config.caches }),
|
|
1014
|
+
...(config.artifacts && { artifacts: config.artifacts }),
|
|
1015
|
+
...(config.environments && { environments: config.environments }),
|
|
1016
|
+
...(config.matrix && { matrix: config.matrix }),
|
|
1017
|
+
...(config.services && { services: config.services }),
|
|
1018
|
+
...(config.concurrency && { concurrency: config.concurrency }),
|
|
1019
|
+
...(config.cicdTriggers && { triggers: config.cicdTriggers }),
|
|
1020
|
+
},
|
|
1021
|
+
}),
|
|
1022
|
+
// Per-target deployment config
|
|
1023
|
+
...(config.deploy && { deploy: config.deploy }),
|
|
997
1024
|
},
|
|
998
1025
|
}),
|
|
999
1026
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI/CD Workflow Detection
|
|
3
|
+
*
|
|
4
|
+
* Determines whether a workflow is a CI/CD pipeline based on annotations.
|
|
5
|
+
* A workflow is CI/CD if it has any CI/CD-specific annotations:
|
|
6
|
+
* @secret, @runner, @cache, @artifact, @environment, @matrix, @service,
|
|
7
|
+
* @concurrency, [job: "..."], or CI/CD trigger types (push, pull_request, etc.)
|
|
8
|
+
*/
|
|
9
|
+
import type { TWorkflowAST } from '../ast/types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Check if a workflow is a CI/CD pipeline.
|
|
12
|
+
*
|
|
13
|
+
* Detection signals (any one is sufficient):
|
|
14
|
+
* 1. Workflow options contain CI/CD fields (secrets, runner, caches, etc.)
|
|
15
|
+
* 2. Any node instance has a `job` attribute
|
|
16
|
+
* 3. Workflow has cicdTriggers
|
|
17
|
+
*/
|
|
18
|
+
export declare function isCICDWorkflow(ast: TWorkflowAST): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Get all unique job names from a CI/CD workflow.
|
|
21
|
+
* Returns empty array if no jobs are defined.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getJobNames(ast: TWorkflowAST): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Get all declared secret names from a CI/CD workflow.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getDeclaredSecrets(ast: TWorkflowAST): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Get all secret:NAME references from connections.
|
|
30
|
+
* Returns array of secret names that are wired via @connect.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getReferencedSecrets(ast: TWorkflowAST): string[];
|
|
33
|
+
//# sourceMappingURL=cicd-detection.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI/CD Workflow Detection
|
|
3
|
+
*
|
|
4
|
+
* Determines whether a workflow is a CI/CD pipeline based on annotations.
|
|
5
|
+
* A workflow is CI/CD if it has any CI/CD-specific annotations:
|
|
6
|
+
* @secret, @runner, @cache, @artifact, @environment, @matrix, @service,
|
|
7
|
+
* @concurrency, [job: "..."], or CI/CD trigger types (push, pull_request, etc.)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if a workflow is a CI/CD pipeline.
|
|
11
|
+
*
|
|
12
|
+
* Detection signals (any one is sufficient):
|
|
13
|
+
* 1. Workflow options contain CI/CD fields (secrets, runner, caches, etc.)
|
|
14
|
+
* 2. Any node instance has a `job` attribute
|
|
15
|
+
* 3. Workflow has cicdTriggers
|
|
16
|
+
*/
|
|
17
|
+
export function isCICDWorkflow(ast) {
|
|
18
|
+
// Check CI/CD domain annotations
|
|
19
|
+
const cicd = ast.options?.cicd;
|
|
20
|
+
if (cicd) {
|
|
21
|
+
if (cicd.secrets && cicd.secrets.length > 0)
|
|
22
|
+
return true;
|
|
23
|
+
if (cicd.runner)
|
|
24
|
+
return true;
|
|
25
|
+
if (cicd.caches && cicd.caches.length > 0)
|
|
26
|
+
return true;
|
|
27
|
+
if (cicd.artifacts && cicd.artifacts.length > 0)
|
|
28
|
+
return true;
|
|
29
|
+
if (cicd.environments && cicd.environments.length > 0)
|
|
30
|
+
return true;
|
|
31
|
+
if (cicd.matrix)
|
|
32
|
+
return true;
|
|
33
|
+
if (cicd.services && cicd.services.length > 0)
|
|
34
|
+
return true;
|
|
35
|
+
if (cicd.concurrency)
|
|
36
|
+
return true;
|
|
37
|
+
if (cicd.triggers && cicd.triggers.length > 0)
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// Check node-level CI/CD annotations
|
|
41
|
+
if (ast.instances.some((inst) => inst.job))
|
|
42
|
+
return true;
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get all unique job names from a CI/CD workflow.
|
|
47
|
+
* Returns empty array if no jobs are defined.
|
|
48
|
+
*/
|
|
49
|
+
export function getJobNames(ast) {
|
|
50
|
+
const jobs = new Set();
|
|
51
|
+
for (const inst of ast.instances) {
|
|
52
|
+
if (inst.job)
|
|
53
|
+
jobs.add(inst.job);
|
|
54
|
+
}
|
|
55
|
+
return Array.from(jobs);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get all declared secret names from a CI/CD workflow.
|
|
59
|
+
*/
|
|
60
|
+
export function getDeclaredSecrets(ast) {
|
|
61
|
+
return (ast.options?.cicd?.secrets || []).map((s) => s.name);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get all secret:NAME references from connections.
|
|
65
|
+
* Returns array of secret names that are wired via @connect.
|
|
66
|
+
*/
|
|
67
|
+
export function getReferencedSecrets(ast) {
|
|
68
|
+
const secrets = new Set();
|
|
69
|
+
for (const conn of ast.connections) {
|
|
70
|
+
if (conn.from.node.startsWith('secret:')) {
|
|
71
|
+
secrets.add(conn.from.node.substring(7)); // strip "secret:" prefix
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return Array.from(secrets);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=cicd-detection.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI/CD-Specific Validation Rules
|
|
3
|
+
*
|
|
4
|
+
* Custom TValidationRule implementations for CI/CD pipeline workflows.
|
|
5
|
+
* These run AFTER the built-in validator via the api/validate.ts custom rules injection.
|
|
6
|
+
*
|
|
7
|
+
* Rules:
|
|
8
|
+
* 1. CICD_SECRET_NOT_DECLARED - secret:X referenced but no @secret X declared
|
|
9
|
+
* 2. CICD_SECRET_UNUSED - @secret X declared but never wired
|
|
10
|
+
* 3. CICD_TRIGGER_MISSING - No trigger annotations — pipeline would never run
|
|
11
|
+
* 4. CICD_JOB_MISSING_RUNNER - Job has no runner (uses workflow default or none)
|
|
12
|
+
* 5. CICD_ARTIFACT_CROSS_JOB - Data flows between jobs without @artifact declaration
|
|
13
|
+
* 6. CICD_CIRCULAR_JOB_DEPS - Job dependency cycle detected
|
|
14
|
+
* 7. CICD_MATRIX_WITH_ENVIRONMENT - Matrix + environment = N approval prompts
|
|
15
|
+
*/
|
|
16
|
+
import type { TValidationRule } from '../ast/types.js';
|
|
17
|
+
/**
|
|
18
|
+
* A `secret:X` pseudo-node is referenced in @connect but no `@secret X` is declared.
|
|
19
|
+
* This means the export target won't know about the secret and can't generate
|
|
20
|
+
* proper environment variable references.
|
|
21
|
+
*/
|
|
22
|
+
export declare const secretNotDeclaredRule: TValidationRule;
|
|
23
|
+
/**
|
|
24
|
+
* A `@secret X` is declared but never wired via `@connect secret:X -> ...`.
|
|
25
|
+
* The secret might be intentional (used in a shell-command step) or a leftover.
|
|
26
|
+
*/
|
|
27
|
+
export declare const secretUnusedRule: TValidationRule;
|
|
28
|
+
/**
|
|
29
|
+
* A CI/CD workflow with no trigger annotations would never run automatically.
|
|
30
|
+
* Needs at least one @trigger (push, pull_request, schedule, dispatch, or tag).
|
|
31
|
+
*/
|
|
32
|
+
export declare const triggerMissingRule: TValidationRule;
|
|
33
|
+
/**
|
|
34
|
+
* A job (group of nodes with same [job: "name"]) has no explicit runner
|
|
35
|
+
* and the workflow has no default @runner. The export target will use a
|
|
36
|
+
* platform default, which may not be what the user expects.
|
|
37
|
+
*/
|
|
38
|
+
export declare const jobMissingRunnerRule: TValidationRule;
|
|
39
|
+
/**
|
|
40
|
+
* Data flows between nodes in different jobs via connections, but no @artifact
|
|
41
|
+
* is declared. In CI/CD, each job runs in a fresh environment — data must be
|
|
42
|
+
* explicitly passed via artifacts.
|
|
43
|
+
*/
|
|
44
|
+
export declare const artifactCrossJobRule: TValidationRule;
|
|
45
|
+
/**
|
|
46
|
+
* Job dependencies (derived from @path connections between jobs) form a cycle.
|
|
47
|
+
* CI/CD platforms reject circular job dependencies.
|
|
48
|
+
*/
|
|
49
|
+
export declare const circularJobDepsRule: TValidationRule;
|
|
50
|
+
/**
|
|
51
|
+
* Using @matrix with @environment protection means each matrix combination
|
|
52
|
+
* triggers an approval prompt. For a 3x2 matrix, that's 6 prompts.
|
|
53
|
+
*/
|
|
54
|
+
export declare const matrixWithEnvironmentRule: TValidationRule;
|
|
55
|
+
/** All CI/CD validation rules */
|
|
56
|
+
export declare const cicdValidationRules: TValidationRule[];
|
|
57
|
+
/**
|
|
58
|
+
* Get all CI/CD validation rules.
|
|
59
|
+
* Convenience function for passing to validateWorkflow().
|
|
60
|
+
*/
|
|
61
|
+
export declare function getCICDValidationRules(): TValidationRule[];
|
|
62
|
+
//# sourceMappingURL=cicd-rules.d.ts.map
|