@orsetra/camel-pom-gen 1.0.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.
@@ -0,0 +1,23 @@
1
+ import { CAMEL_CATALOG_3_15_3 } from './catalog-3.15.3'
2
+ // Add when available: import { CAMEL_CATALOG_3_39_X } from './catalog-3.39.x'
3
+
4
+ import { parseCatalogYaml } from '../catalog/catalog'
5
+ import type { CamelCatalog } from '../catalog/types'
6
+
7
+ const BUNDLED_CATALOGS: Record<string, string> = {
8
+ '3.15.3': CAMEL_CATALOG_3_15_3,
9
+ // '3.39.x': CAMEL_CATALOG_3_39_X,
10
+ }
11
+
12
+ /**
13
+ * Get a bundled CamelCatalog by catalogVersion (e.g. "3.15.3").
14
+ * Returns undefined if the version is not bundled — caller should
15
+ * fall back to a user-provided catalog via parseCatalogYaml().
16
+ */
17
+ export function getBundledCatalog(catalogVersion: string): CamelCatalog | undefined {
18
+ const raw = BUNDLED_CATALOGS[catalogVersion]
19
+ return raw ? parseCatalogYaml(raw) : undefined
20
+ }
21
+
22
+ /** All bundled catalog versions. */
23
+ export const BUNDLED_CATALOG_VERSIONS = Object.keys(BUNDLED_CATALOGS)
package/src/config.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Runtime configuration aligned with official Camel K operator releases.
3
+ *
4
+ * Sources:
5
+ * - pkg/util/defaults/defaults.go (per tag in the repo)
6
+ * - pkg/builder/quarkus.go → generateQuarkusProjectCommon
7
+ * - https://camel.apache.org/blog/2026/09/camel-k-2-11/
8
+ */
9
+
10
+ export type RuntimeFlavor = 'plain-quarkus' | 'quarkus'
11
+
12
+ export interface CamelKRuntimeConfig {
13
+ /** Camel K operator version (e.g. "2.11.0"). */
14
+ operatorVersion: string
15
+ /** DSL runtime flavor. */
16
+ flavor: RuntimeFlavor
17
+ /**
18
+ * For plain-quarkus: Quarkus Platform version used as BOM version AND as
19
+ * quarkus-maven-plugin version (matches `runtimeVersion` in defaults.go).
20
+ * For legacy quarkus: camel-k-runtime BOM version.
21
+ */
22
+ runtimeVersion: string
23
+ /**
24
+ * For legacy quarkus: the Quarkus version from the catalog metadata
25
+ * (catalog.runtime.metadata["quarkus.version"]) — used as quarkus-maven-plugin
26
+ * version only.
27
+ * For plain-quarkus: same as runtimeVersion (field can be omitted).
28
+ */
29
+ quarkusPlatformVersion?: string
30
+ /** Human-readable Camel core version shipped with this config. */
31
+ camelVersion: string
32
+ /** Catalog YAML file version (camel-catalog-<catalogVersion>.yaml). */
33
+ catalogVersion: string
34
+ }
35
+
36
+ /** Resolved quarkus-maven-plugin version for the given config. */
37
+ export function getQuarkusPluginVersion(config: CamelKRuntimeConfig): string {
38
+ if (config.flavor === 'plain-quarkus') return config.runtimeVersion
39
+ return config.quarkusPlatformVersion ?? config.runtimeVersion
40
+ }
41
+
42
+ /**
43
+ * Known Camel K release → runtime mappings.
44
+ * Add new entries when upgrading the operator.
45
+ */
46
+ export const OPERATOR_RUNTIME_CONFIGS: CamelKRuntimeConfig[] = [
47
+ {
48
+ operatorVersion: '2.11.0',
49
+ flavor: 'plain-quarkus',
50
+ runtimeVersion: '3.39.1', // Quarkus Platform — BOM + plugin version
51
+ camelVersion: '4.22.0',
52
+ catalogVersion: '3.15.3',
53
+ },
54
+ {
55
+ operatorVersion: '2.10.0',
56
+ flavor: 'quarkus',
57
+ runtimeVersion: '3.15.3', // camel-k-runtime BOM version
58
+ quarkusPlatformVersion: '3.15.4', // quarkus.version from catalog metadata
59
+ camelVersion: '4.8.5',
60
+ catalogVersion: '3.15.3',
61
+ },
62
+ {
63
+ operatorVersion: '2.9.0',
64
+ flavor: 'quarkus',
65
+ runtimeVersion: '3.14.0',
66
+ quarkusPlatformVersion: '3.14.0',
67
+ camelVersion: '4.7.0',
68
+ catalogVersion: '3.14.0',
69
+ },
70
+ ]
71
+
72
+ /** Get the runtime config for a given operator version (exact match, then latest). */
73
+ export function getRuntimeConfig(operatorVersion: string): CamelKRuntimeConfig {
74
+ return OPERATOR_RUNTIME_CONFIGS.find(c => c.operatorVersion === operatorVersion)
75
+ ?? OPERATOR_RUNTIME_CONFIGS[0]
76
+ }
77
+
78
+ /** Default config (latest supported operator version). */
79
+ export const DEFAULT_CONFIG = OPERATOR_RUNTIME_CONFIGS[0]
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Dependency manager — mirrors pkg/util/camel/camel_dependencies.go.
3
+ */
4
+ import type { CamelCatalog } from '../catalog/types'
5
+ import type { MavenDependency, MavenProject, MavenRepository } from './types'
6
+
7
+ const JITPACK_REPO_URL = 'https://jitpack.io'
8
+ const QUARKUS_GROUP_ID = 'org.apache.camel.quarkus'
9
+
10
+ // ─── Project factory ──────────────────────────────────────────────────────────
11
+
12
+ export function createProject(groupId: string, artifactId: string, version: string): MavenProject {
13
+ return {
14
+ groupId,
15
+ artifactId,
16
+ version,
17
+ properties: {},
18
+ boms: [],
19
+ dependencies: [],
20
+ exclusions: new Map(),
21
+ repositories: [],
22
+ pluginRepositories: [],
23
+ build: { plugins: [] },
24
+ profiles: [],
25
+ }
26
+ }
27
+
28
+ // ─── Dependency adders ────────────────────────────────────────────────────────
29
+
30
+ /** Add a Maven dependency (deduplicates by groupId:artifactId). */
31
+ export function addDependency(project: MavenProject, dep: MavenDependency): void {
32
+ const key = `${dep.groupId}:${dep.artifactId}`
33
+ if (!project.dependencies.some(d => `${d.groupId}:${d.artifactId}` === key)) {
34
+ project.dependencies.push(dep)
35
+ }
36
+ }
37
+
38
+ export function addDependencyGAV(project: MavenProject, groupId: string, artifactId: string, version = ''): void {
39
+ addDependency(project, { groupId, artifactId, ...(version ? { version } : {}) })
40
+ }
41
+
42
+ /**
43
+ * Process a raw dependency string (camel:xxx, mvn:g:a:v, bom:g:a:v,
44
+ * camel-k:xxx, camel-quarkus:xxx, or a GitHub JitPack coords).
45
+ */
46
+ export function applyDependency(
47
+ project: MavenProject,
48
+ catalog: CamelCatalog,
49
+ dep: string,
50
+ ): string | null {
51
+ if (dep.startsWith('bom:')) return applyBOM(project, dep)
52
+ if (dep.startsWith('camel:')) { applyCamelComponent(project, catalog, dep); return null }
53
+ if (dep.startsWith('camel-k:')) { applyCamelKComponent(project, dep); return null }
54
+ if (dep.startsWith('camel-quarkus:')) { applyCamelQuarkusComponent(project, dep); return null }
55
+ if (dep.startsWith('mvn:')) { applyMavenDependency(project, dep); return null }
56
+ if (dep.startsWith('github:')) return applyJitPack(project, dep)
57
+ return `Unknown dependency format: ${dep}`
58
+ }
59
+
60
+ function applyBOM(project: MavenProject, dep: string): string | null {
61
+ const gav = dep.slice('bom:'.length)
62
+ const parts = gav.split(':')
63
+ if (parts.length < 3) return `Invalid BOM format: ${dep}`
64
+ project.boms.push({ groupId: parts[0], artifactId: parts[1], version: parts[2] })
65
+ return null
66
+ }
67
+
68
+ function applyCamelComponent(project: MavenProject, catalog: CamelCatalog, dep: string): void {
69
+ let artifactId = dep.slice('camel:'.length)
70
+ const isQuarkus = catalog.runtime.provider === 'quarkus' || catalog.runtime.provider === 'plain-quarkus'
71
+ if (isQuarkus) {
72
+ if (!artifactId.startsWith('camel-')) artifactId = 'camel-quarkus-' + artifactId
73
+ addDependencyGAV(project, QUARKUS_GROUP_ID, artifactId)
74
+ } else {
75
+ if (!artifactId.startsWith('camel-')) artifactId = 'camel-' + artifactId
76
+ addDependencyGAV(project, 'org.apache.camel', artifactId)
77
+ }
78
+ }
79
+
80
+ function applyCamelKComponent(project: MavenProject, dep: string): void {
81
+ let artifactId = dep.slice('camel-k:'.length)
82
+ if (!artifactId.startsWith('camel-k-')) artifactId = 'camel-k-' + artifactId
83
+ addDependencyGAV(project, 'org.apache.camel.k', artifactId)
84
+ }
85
+
86
+ function applyCamelQuarkusComponent(project: MavenProject, dep: string): void {
87
+ let artifactId = dep.slice('camel-quarkus:'.length)
88
+ if (!artifactId.startsWith('camel-quarkus-')) artifactId = 'camel-quarkus-' + artifactId
89
+ addDependencyGAV(project, QUARKUS_GROUP_ID, artifactId)
90
+ }
91
+
92
+ /** `mvn:groupId:artifactId` or `mvn:groupId:artifactId:version` */
93
+ function applyMavenDependency(project: MavenProject, dep: string): void {
94
+ const gav = dep.slice('mvn:'.length)
95
+ const parts = gav.split(':')
96
+ if (parts.length >= 2) addDependencyGAV(project, parts[0], parts[1], parts[2])
97
+ }
98
+
99
+ function applyJitPack(project: MavenProject, dep: string): string | null {
100
+ const coords = dep.slice('github:'.length)
101
+ const parts = coords.split('/')
102
+ if (parts.length < 3) return `Invalid JitPack format: ${dep}`
103
+ const [org, repo, version] = parts
104
+ addDependency(project, { groupId: `com.github.${org}`, artifactId: repo, version })
105
+ addJitPackRepo(project)
106
+ return null
107
+ }
108
+
109
+ function addJitPackRepo(project: MavenProject): void {
110
+ if (!project.repositories.some(r => r.url === JITPACK_REPO_URL)) {
111
+ const repo: MavenRepository = {
112
+ id: 'jitpack.io',
113
+ url: JITPACK_REPO_URL,
114
+ releases: { enabled: true, checksumPolicy: 'fail' },
115
+ snapshots: { enabled: true, checksumPolicy: 'fail' },
116
+ }
117
+ project.repositories.push(repo)
118
+ }
119
+ }
120
+
121
+ // ─── Post-processing ──────────────────────────────────────────────────────────
122
+
123
+ /**
124
+ * Add transitive dependencies from the catalog for every artifact already in the project.
125
+ * Mirrors addDependenciesFromCatalog() in camel_dependencies.go.
126
+ */
127
+ export function addTransitiveDeps(project: MavenProject, catalog: CamelCatalog): void {
128
+ const snapshot = [...project.dependencies]
129
+ for (const dep of snapshot) {
130
+ const artifact = catalog.artifacts[dep.artifactId]
131
+ if (!artifact) continue
132
+ for (const transitive of artifact.dependencies ?? []) {
133
+ addDependency(project, {
134
+ groupId: transitive.groupId,
135
+ artifactId: transitive.artifactId,
136
+ ...(transitive.type ? { type: transitive.type } : {}),
137
+ ...(transitive.classifier ? { classifier: transitive.classifier } : {}),
138
+ })
139
+ }
140
+ const key = `${artifact.groupId}:${artifact.artifactId}`
141
+ const excls = artifact.exclusions ?? []
142
+ if (excls.length > 0) {
143
+ project.exclusions.set(key, [...(project.exclusions.get(key) ?? []), ...excls])
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Strip versions from Camel/Camel-K/Camel-Quarkus artifacts so the BOM manages them.
150
+ * Mirrors SanitizeIntegrationDependencies() in camel_dependencies.go.
151
+ */
152
+ export function sanitizeDependencies(project: MavenProject): void {
153
+ const managed = new Set(['org.apache.camel', 'org.apache.camel.k', 'org.apache.camel.quarkus'])
154
+ for (const dep of project.dependencies) {
155
+ if (managed.has(dep.groupId)) dep.version = undefined
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Apply all dependency strings, resolve transitives, and sanitize versions.
161
+ * Mirrors ManageIntegrationDependencies() in camel_dependencies.go.
162
+ */
163
+ export function manageIntegrationDependencies(
164
+ project: MavenProject,
165
+ catalog: CamelCatalog,
166
+ dependencies: string[],
167
+ ): string[] {
168
+ const errors: string[] = []
169
+ for (const dep of dependencies) {
170
+ const err = applyDependency(project, catalog, dep)
171
+ if (err) errors.push(err)
172
+ }
173
+ addTransitiveDeps(project, catalog)
174
+ sanitizeDependencies(project)
175
+ return errors
176
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Dependency normalizer — mirrors pkg/util/camel/camel_dependencies.go → NormalizeDependency.
3
+ *
4
+ * Converts all the forms accepted by kamel CLI into the canonical `camel:xxx` form:
5
+ * camel-timer → camel:timer
6
+ * camel-quarkus-timer → camel:timer
7
+ * camel-quarkus:timer → camel:timer
8
+ * camel-k-cron → camel-k:cron
9
+ */
10
+ export function normalizeDependency(dep: string): string {
11
+ if (dep.startsWith('camel-quarkus-')) return 'camel:' + dep.slice('camel-quarkus-'.length)
12
+ if (dep.startsWith('camel-quarkus:')) return 'camel:' + dep.slice('camel-quarkus:'.length)
13
+ if (dep.startsWith('camel-k-')) return 'camel-k:' + dep.slice('camel-k-'.length)
14
+ if (dep.startsWith('camel-k:')) return dep
15
+ if (dep.startsWith('camel-')) return 'camel:' + dep.slice('camel-'.length)
16
+ return dep
17
+ }
18
+
19
+ /** Validate that a `camel:xxx` dependency exists in the catalog artifacts. */
20
+ export function validateCamelDep(artifactKeys: Set<string>, dep: string): boolean {
21
+ if (dep.startsWith('camel:')) {
22
+ const name = dep.slice('camel:'.length)
23
+ // catalog keys are like "camel-quarkus-timer"
24
+ return artifactKeys.has('camel-quarkus-' + name) || artifactKeys.has('camel-' + name)
25
+ }
26
+ return true
27
+ }
@@ -0,0 +1,75 @@
1
+ export interface MavenDependency {
2
+ groupId: string
3
+ artifactId: string
4
+ version?: string
5
+ scope?: string
6
+ type?: string
7
+ classifier?: string
8
+ }
9
+
10
+ export interface MavenExclusion {
11
+ groupId: string
12
+ artifactId: string
13
+ }
14
+
15
+ export interface MavenExecution {
16
+ id?: string
17
+ phase?: string
18
+ goals: string[]
19
+ }
20
+
21
+ export interface MavenPlugin {
22
+ groupId: string
23
+ artifactId: string
24
+ version?: string
25
+ /** <extensions>true</extensions> — required by quarkus-maven-plugin */
26
+ extensions?: boolean
27
+ executions?: MavenExecution[]
28
+ dependencies?: MavenDependency[]
29
+ /** Raw XML string injected verbatim inside <configuration>...</configuration> */
30
+ configurationXml?: string
31
+ }
32
+
33
+ export interface MavenProfile {
34
+ id: string
35
+ activeByDefault?: boolean
36
+ /** Plugins in the profile's <build> section */
37
+ plugins?: MavenPlugin[]
38
+ /** Raw XML string injected verbatim for the entire profile when needed */
39
+ rawXml?: string
40
+ }
41
+
42
+ export interface MavenRepository {
43
+ id: string
44
+ url: string
45
+ name?: string
46
+ releases?: { enabled: boolean; checksumPolicy?: string }
47
+ snapshots?: { enabled: boolean; checksumPolicy?: string }
48
+ }
49
+
50
+ export interface MavenBOM {
51
+ groupId: string
52
+ artifactId: string
53
+ version: string
54
+ }
55
+
56
+ /**
57
+ * In-memory representation of a Maven project before serialization.
58
+ * Mirrors pkg/util/maven/maven_types.go → Project struct.
59
+ */
60
+ export interface MavenProject {
61
+ groupId: string
62
+ artifactId: string
63
+ version: string
64
+ properties: Record<string, string>
65
+ /** BOM imports (dependencyManagement) */
66
+ boms: MavenBOM[]
67
+ dependencies: MavenDependency[]
68
+ exclusions: Map<string, MavenExclusion[]> // key = "groupId:artifactId"
69
+ repositories: MavenRepository[]
70
+ pluginRepositories: MavenRepository[]
71
+ build: {
72
+ plugins: MavenPlugin[]
73
+ }
74
+ profiles: MavenProfile[]
75
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * FileSystemProvider — abstraction over file system access.
3
+ *
4
+ * The package never touches the real filesystem directly.
5
+ * The host IDE registers an implementation at startup via init().
6
+ *
7
+ * Two reference implementations:
8
+ * nodeFsProvider(fs) — Node.js fs module (desktop / server-side IDE)
9
+ * memFsProvider(map) — in-memory map (tests, browser IDEs with files already loaded)
10
+ */
11
+ export interface FileSystemProvider {
12
+ /**
13
+ * Read a file and return its UTF-8 content.
14
+ * Throw / reject when the file does not exist.
15
+ */
16
+ readFile(path: string): string | Promise<string>
17
+
18
+ /**
19
+ * List all files recursively under `dir`.
20
+ * Returns full paths (same format as the paths passed to readFile).
21
+ * Returns an empty array when the directory does not exist.
22
+ */
23
+ listFiles(dir: string): string[] | Promise<string[]>
24
+ }
25
+
26
+ // ── Registry ──────────────────────────────────────────────────────────────────
27
+
28
+ let _fs: FileSystemProvider | undefined
29
+
30
+ export function registerFsProvider(provider: FileSystemProvider): void {
31
+ _fs = provider
32
+ }
33
+
34
+ export function getFsProvider(): FileSystemProvider {
35
+ if (!_fs) throw new Error(
36
+ '[camel-pom-gen] No FileSystemProvider registered. ' +
37
+ 'Call init() before syncPom().',
38
+ )
39
+ return _fs
40
+ }
41
+
42
+ // ── Reference implementations ─────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Node.js provider.
46
+ * Pass the `fs` module (or `fs/promises`) and the `path` module.
47
+ *
48
+ * @example
49
+ * import fs from 'fs'
50
+ * import path from 'path'
51
+ * init({ ..., fs: nodeFsProvider(fs, path) })
52
+ */
53
+ export function nodeFsProvider(
54
+ nodeFs: {
55
+ readFileSync(p: string, enc: 'utf8'): string
56
+ readdirSync(p: string, opts: { withFileTypes: true }): Array<{ name: string; isDirectory(): boolean }>
57
+ },
58
+ nodePath: { join(...parts: string[]): string },
59
+ ): FileSystemProvider {
60
+ function walk(dir: string): string[] {
61
+ let entries: Array<{ name: string; isDirectory(): boolean }>
62
+ try { entries = nodeFs.readdirSync(dir, { withFileTypes: true }) }
63
+ catch { return [] }
64
+ const files: string[] = []
65
+ for (const e of entries) {
66
+ const full = nodePath.join(dir, e.name)
67
+ if (e.isDirectory()) files.push(...walk(full))
68
+ else files.push(full)
69
+ }
70
+ return files
71
+ }
72
+ return {
73
+ readFile: (p) => nodeFs.readFileSync(p, 'utf8'),
74
+ listFiles: (dir) => walk(dir),
75
+ }
76
+ }
77
+
78
+ /**
79
+ * In-memory provider — map of path → content.
80
+ * listFiles returns all paths that start with the given dir prefix.
81
+ *
82
+ * @example
83
+ * init({ ..., fs: memFsProvider({
84
+ * 'src/main/resources/route.yaml': '...',
85
+ * 'src/main/java/Processor.java': '...',
86
+ * }) })
87
+ */
88
+ export function memFsProvider(files: Record<string, string>): FileSystemProvider {
89
+ return {
90
+ readFile: (path) => {
91
+ if (!(path in files)) throw new Error(`[camel-pom-gen] File not found: ${path}`)
92
+ return files[path]
93
+ },
94
+ listFiles: (dir) => {
95
+ const prefix = dir.endsWith('/') ? dir : dir + '/'
96
+ return Object.keys(files).filter(p => p.startsWith(prefix))
97
+ },
98
+ }
99
+ }