Skip to content

Commit bbf3b41

Browse files
committed
Implement CFG
1 parent e00700f commit bbf3b41

File tree

17 files changed

+1745
-128
lines changed

17 files changed

+1745
-128
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/builders/src/apply-swc-transform.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ export type GraphManifest = {
4646
}>;
4747
};
4848
};
49+
debugInfo?: {
50+
manifestPresent: boolean;
51+
manifestStepFiles: number;
52+
importsResolved: number;
53+
importsWithKind: number;
54+
importDetails: Array<{
55+
localName: string;
56+
source: string;
57+
importedName: string;
58+
kind: string | null;
59+
lookupCandidates: string[];
60+
}>;
61+
};
4962
};
5063

5164
export async function applySwcTransform(
@@ -56,7 +69,8 @@ export async function applySwcTransform(
5669
paths?: Record<string, string[]>;
5770
// this must be absolute path
5871
baseUrl?: string;
59-
}
72+
},
73+
workflowManifest?: WorkflowManifest
6074
): Promise<{
6175
code: string;
6276
workflowManifest: WorkflowManifest;
@@ -78,7 +92,12 @@ export async function applySwcTransform(
7892
target: 'es2022',
7993
experimental: mode
8094
? {
81-
plugins: [[require.resolve('@workflow/swc-plugin'), { mode }]],
95+
plugins: [
96+
[
97+
require.resolve('@workflow/swc-plugin'),
98+
{ mode, workflowManifest },
99+
],
100+
],
82101
}
83102
: undefined,
84103
...jscConfig,

packages/builders/src/base-builder.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const EMIT_SOURCEMAPS_FOR_DEBUGGING =
2626
*/
2727
export abstract class BaseBuilder {
2828
protected config: WorkflowConfig;
29+
protected lastWorkflowManifest?: WorkflowManifest;
2930

3031
constructor(config: WorkflowConfig) {
3132
this.config = config;
@@ -253,6 +254,7 @@ export abstract class BaseBuilder {
253254
* Steps have full Node.js runtime access and handle side effects, API calls, etc.
254255
*
255256
* @param externalizeNonSteps - If true, only bundles step entry points and externalizes other code
257+
* @returns Build context (for watch mode) and the collected workflow manifest
256258
*/
257259
protected async createStepsBundle({
258260
inputFiles,
@@ -268,7 +270,10 @@ export abstract class BaseBuilder {
268270
outfile: string;
269271
format?: 'cjs' | 'esm';
270272
externalizeNonSteps?: boolean;
271-
}): Promise<esbuild.BuildContext | undefined> {
273+
}): Promise<{
274+
context: esbuild.BuildContext | undefined;
275+
manifest: WorkflowManifest;
276+
}> {
272277
// These need to handle watching for dev to scan for
273278
// new entries and changes to existing ones
274279
const { discoveredSteps: stepFiles } = await this.discoverEntries(
@@ -389,10 +394,14 @@ export abstract class BaseBuilder {
389394
// Create .gitignore in .swc directory
390395
await this.createSwcGitignore();
391396

397+
// Store the manifest for later use (e.g., graph generation in watch mode)
398+
this.lastWorkflowManifest = workflowManifest;
399+
392400
if (this.config.watch) {
393-
return esbuildCtx;
401+
return { context: esbuildCtx, manifest: workflowManifest };
394402
}
395403
await esbuildCtx.dispose();
404+
return { context: undefined, manifest: workflowManifest };
396405
}
397406

398407
/**
@@ -848,11 +857,13 @@ export const OPTIONS = handler;`;
848857
outfile,
849858
tsBaseUrl,
850859
tsPaths,
860+
workflowManifest,
851861
}: {
852862
inputFiles: string[];
853863
outfile: string;
854864
tsBaseUrl?: string;
855865
tsPaths?: Record<string, string[]>;
866+
workflowManifest?: WorkflowManifest;
856867
}): Promise<void> {
857868
const graphBuildStart = Date.now();
858869
console.log('Creating workflow graph manifest...');
@@ -867,6 +878,9 @@ export const OPTIONS = handler;`;
867878
return;
868879
}
869880

881+
// Use provided manifest or fall back to last built manifest
882+
const manifest = workflowManifest || this.lastWorkflowManifest;
883+
870884
// Import applySwcTransform dynamically
871885
const { applySwcTransform } = await import('./apply-swc-transform.js');
872886

@@ -896,7 +910,8 @@ export const OPTIONS = handler;`;
896910
{
897911
paths: tsPaths,
898912
baseUrl: tsBaseUrl,
899-
}
913+
},
914+
manifest
900915
);
901916

902917
if (graphManifest && graphManifest.workflows) {
@@ -905,6 +920,11 @@ export const OPTIONS = handler;`;
905920
combinedGraphManifest.workflows,
906921
graphManifest.workflows
907922
);
923+
924+
// Preserve debug info from the first workflow file (for debugging)
925+
if (graphManifest.debugInfo && !combinedGraphManifest.debugInfo) {
926+
combinedGraphManifest.debugInfo = graphManifest.debugInfo;
927+
}
908928
}
909929
} catch (error) {
910930
console.warn(

packages/builders/src/standalone.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export class StandaloneBuilder extends BaseBuilder {
1010
tsBaseUrl: tsConfig.baseUrl,
1111
tsPaths: tsConfig.paths,
1212
};
13-
await this.buildStepsBundle(options);
13+
const workflowManifest = await this.buildStepsBundle(options);
1414
await this.buildWorkflowsBundle(options);
1515
await this.buildWebhookFunction();
16-
await this.buildGraphManifest(options);
16+
await this.buildGraphManifest({ ...options, workflowManifest });
1717

1818
await this.createClientLibrary();
1919
}
@@ -26,18 +26,20 @@ export class StandaloneBuilder extends BaseBuilder {
2626
inputFiles: string[];
2727
tsBaseUrl?: string;
2828
tsPaths?: Record<string, string[]>;
29-
}): Promise<void> {
29+
}) {
3030
console.log('Creating steps bundle at', this.config.stepsBundlePath);
3131

3232
const stepsBundlePath = this.resolvePath(this.config.stepsBundlePath);
3333
await this.ensureDirectory(stepsBundlePath);
3434

35-
await this.createStepsBundle({
35+
const { manifest } = await this.createStepsBundle({
3636
outfile: stepsBundlePath,
3737
inputFiles,
3838
tsBaseUrl,
3939
tsPaths,
4040
});
41+
42+
return manifest;
4143
}
4244

4345
private async buildWorkflowsBundle({
@@ -82,10 +84,12 @@ export class StandaloneBuilder extends BaseBuilder {
8284
inputFiles,
8385
tsPaths,
8486
tsBaseUrl,
87+
workflowManifest,
8588
}: {
8689
inputFiles: string[];
8790
tsBaseUrl?: string;
8891
tsPaths?: Record<string, string[]>;
92+
workflowManifest?: import('./apply-swc-transform.js').WorkflowManifest;
8993
}): Promise<void> {
9094
const graphManifestPath = this.resolvePath('.swc/graph-manifest.json');
9195
await this.ensureDirectory(graphManifestPath);
@@ -95,6 +99,7 @@ export class StandaloneBuilder extends BaseBuilder {
9599
outfile: graphManifestPath,
96100
tsBaseUrl,
97101
tsPaths,
102+
workflowManifest,
98103
});
99104
}
100105
}

packages/next/src/builder.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export async function getNextBuilder() {
4343
tsPaths: tsConfig.paths,
4444
};
4545

46-
const stepsBuildContext = await this.buildStepsFunction(options);
46+
const { context: stepsBuildContext, manifest: workflowManifest } =
47+
await this.buildStepsFunction(options);
4748
const workflowsBundle = await this.buildWorkflowsFunction(options);
4849
await this.buildWebhookRoute({ workflowGeneratedDir });
4950

@@ -58,6 +59,7 @@ export async function getNextBuilder() {
5859
outfile: join(workflowDataDir, 'graph-manifest.json'),
5960
tsBaseUrl: options.tsBaseUrl,
6061
tsPaths: options.tsPaths,
62+
workflowManifest,
6163
});
6264

6365
await this.writeFunctionsConfig(outputDir);
@@ -164,7 +166,8 @@ export async function getNextBuilder() {
164166
options.inputFiles = newInputFiles;
165167

166168
await stepsCtx.dispose();
167-
const newStepsCtx = await this.buildStepsFunction(options);
169+
const { context: newStepsCtx } =
170+
await this.buildStepsFunction(options);
168171
if (!newStepsCtx) {
169172
throw new Error(
170173
'Invariant: expected steps build context after rebuild'

packages/swc-plugin-workflow/src/lib.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ use swc_core::{
99
use swc_workflow::{StepTransform, TransformMode};
1010

1111
#[derive(Deserialize)]
12-
#[serde(rename_all = "camelCase", deny_unknown_fields)]
12+
#[serde(rename_all = "camelCase")]
1313
struct WasmConfig {
1414
mode: TransformMode,
15+
#[serde(default)]
16+
workflow_manifest: Option<swc_workflow::WorkflowManifest>,
1517
}
1618

1719
#[plugin_transform]
@@ -26,30 +28,33 @@ pub fn process_transform(
2628
)
2729
.expect("Should provide plugin config");
2830

29-
let filename = metadata.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Filename)
31+
let filename = metadata
32+
.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Filename)
3033
.unwrap_or_else(|| "unknown".to_string());
31-
34+
3235
// Try to get cwd and make the path relative
33-
let cwd = metadata.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Cwd);
34-
36+
let cwd =
37+
metadata.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Cwd);
38+
3539
let relative_filename = if let Some(cwd) = cwd {
3640
let cwd_path = Path::new(&cwd);
3741
let file_path = Path::new(&filename);
38-
42+
3943
// Try to strip the cwd prefix to make it relative
4044
if let Ok(relative) = file_path.strip_prefix(cwd_path) {
4145
relative.to_string_lossy().to_string()
4246
} else {
4347
// Find common ancestor path
4448
let cwd_components: Vec<_> = cwd_path.components().collect();
4549
let file_components: Vec<_> = file_path.components().collect();
46-
50+
4751
// Find the longest common prefix
48-
let common_len = cwd_components.iter()
52+
let common_len = cwd_components
53+
.iter()
4954
.zip(file_components.iter())
5055
.take_while(|(a, b)| a == b)
5156
.count();
52-
57+
5358
if common_len > 0 {
5459
// Build relative path from the common ancestor
5560
let remaining_file: Vec<_> = file_components.into_iter().skip(common_len).collect();
@@ -62,11 +67,15 @@ pub fn process_transform(
6267
} else {
6368
filename
6469
};
65-
70+
6671
// Normalize path separators to forward slashes for consistent workflow IDs across platforms
6772
let normalized_filename = relative_filename.replace('\\', "/");
68-
69-
let mut visitor = StepTransform::new(plugin_config.mode, normalized_filename);
73+
74+
let mut visitor = StepTransform::new(
75+
plugin_config.mode,
76+
normalized_filename,
77+
plugin_config.workflow_manifest,
78+
);
7079
program.visit_mut_with(&mut visitor);
7180
program
7281
}

packages/swc-plugin-workflow/transform/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ version = "0.1.0"
1313
[dependencies]
1414
serde = { workspace = true }
1515
serde_json = { workspace = true }
16-
swc_core = { workspace = true, features = ["ecma_plugin_transform"] }
16+
swc_core = { workspace = true, features = ["ecma_plugin_transform", "ecma_parser"] }
1717

1818
[dev-dependencies]
1919
testing = { workspace = true }

0 commit comments

Comments
 (0)