ResolversReference
Project Structure
Standard file layout for resolver projects
Project Structure
A resolver project follows a standard layout for consistency and ease of development.
Basic Structure
index.ts
package.json
bun.lock
Dockerfile
cyan.yaml
tsconfig.json
main.py
requirements.txt
Dockerfile
cyan.yaml
Program.cs
MyResolver.csproj
Dockerfile
cyan.yaml
File Descriptions
Entry Point File
The main entry point using StartResolverWithLambda:
index.ts
import { ResolverOutput, StartResolverWithLambda } from '@atomicloud/cyan-sdk';StartResolverWithLambda(async (input): Promise<ResolverOutput> => {// Sort files by layerconst sorted = [...input.files].sort((a, b) => a.origin.layer - b.origin.layer);// Merge contentlet merged = {};for (const file of sorted) {merged = { ...merged, ...JSON.parse(file.content) };}return {path: input.files[0].path,content: JSON.stringify(merged, null, 2)};});
The main entry point using start_resolver_with_fn:
main.py
import jsonfrom cyanprintsdk.resolver import start_resolver_with_fnfrom cyanprintsdk.protocol import ResolverInput, ResolverOutputasync def resolver(input: ResolverInput) -> ResolverOutput:# Sort files by layersorted_files = sorted(input.files, key=lambda f: f.origin.layer)# Merge contentmerged = {}for file in sorted_files:merged = {**merged, **json.loads(file.content)}return ResolverOutput(path=input.files[0].path,content=json.dumps(merged, indent=2))resolver_main = start_resolver_with_fn(resolver)
The main entry point using CyanEngine.StartResolver:
Program.cs
using CyanPrintSDK;using System.Text.Json;public static class Resolver{public static async Task Main(string[] args){CyanEngine.StartResolver(args, Resolve);}private static Task<ResolverOutput> Resolve(ResolverInput input){// Sort files by layervar sorted = input.Files.OrderBy(f => f.Origin.Layer).ToList();// Merge contentvar merged = new Dictionary<string, object>();foreach (var file in sorted){var content = JsonSerializer.Deserialize<Dictionary<string, object>>(file.Content);if (content != null){foreach (var kvp in content)merged[kvp.Key] = kvp.Value;}}return Task.FromResult(new ResolverOutput(input.Files[0].Path,JsonSerializer.Serialize(merged, new JsonSerializerOptions { WriteIndented = true })));}}
Dependency File
Define dependencies and scripts in package.json:
package.json
{"name": "my-resolver","version": "1.0.0","type": "module","scripts": {"start": "bun run index.ts"},"dependencies": {"@atomicloud/cyan-sdk": "^1.0.0"},"devDependencies": {"@types/bun": "latest"}}
Define dependencies in requirements.txt:
requirements.txt
cyanprintsdk>=1.0.0
Define dependencies in .csproj:
MyResolver.csproj
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Sulfone.Helium" Version="1.0.0" /></ItemGroup></Project>
Dockerfile
Container definition for the resolver:
Dockerfile
FROM oven/bun:1.1.30WORKDIR /app# Required: Mark as CyanPrint resolverLABEL cyanprint.dev=true# Install dependenciesCOPY package.json .COPY bun.lock .RUN bun install# Copy resolver codeCOPY . .# Run resolverCMD ["bun", "run", "index.ts"]
Container definition for the resolver:
Dockerfile
FROM python:3.11-slimWORKDIR /app# Required: Mark as CyanPrint resolverLABEL cyanprint.dev=true# Install dependenciesCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt# Copy resolver codeCOPY . .# Run resolverCMD ["python", "main.py"]
Container definition for the resolver:
Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS buildWORKDIR /app# Required: Mark as CyanPrint resolverLABEL cyanprint.dev=true# BuildCOPY *.csproj .RUN dotnet restoreCOPY . .RUN dotnet publish -c Release -o out# RuntimeFROM mcr.microsoft.com/dotnet/runtime:8.0WORKDIR /appCOPY --from=build /app/out .CMD ["dotnet", "MyResolver.dll"]
The LABEL cyanprint.dev=true line is required for the container to be recognized as a CyanPrint resolver.
cyan.yaml
Metadata for registry publishing:
cyan.yaml
username: your-usernamename: my-resolverdescription: JSON file resolver for layered templatesproject: https://github.com/org/my-projectsource: https://github.com/org/my-resolvertags:- json- merge- resolverreadme: README.md
tsconfig.json
TypeScript configuration
tsconfig.json
{"compilerOptions": {"target": "ES2022","module": "ESNext","moduleResolution": "bundler","strict": true,"skipLibCheck": true,"esModuleInterop": true},"include": ["*.ts", "src/**/*.ts"]}
Optional Directories
src/
Organize larger resolvers into modules
index.ts
tests/
Unit tests for resolver logic
merge.test.ts
utils.test.ts