@docker-harpoon/core 0.1.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/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +10 -0
- package/dist/api/promise.d.ts +179 -0
- package/dist/api/promise.d.ts.map +1 -0
- package/dist/api/promise.js +282 -0
- package/dist/bindings/index.d.ts +8 -0
- package/dist/bindings/index.d.ts.map +1 -0
- package/dist/bindings/index.js +6 -0
- package/dist/bindings/types.d.ts +116 -0
- package/dist/bindings/types.d.ts.map +1 -0
- package/dist/bindings/types.js +46 -0
- package/dist/build-strategies/index.d.ts +30 -0
- package/dist/build-strategies/index.d.ts.map +1 -0
- package/dist/build-strategies/index.js +47 -0
- package/dist/build-strategies/standard.d.ts +16 -0
- package/dist/build-strategies/standard.d.ts.map +1 -0
- package/dist/build-strategies/standard.js +39 -0
- package/dist/build-strategies/types.d.ts +81 -0
- package/dist/build-strategies/types.d.ts.map +1 -0
- package/dist/build-strategies/types.js +25 -0
- package/dist/config-patchers/index.d.ts +33 -0
- package/dist/config-patchers/index.d.ts.map +1 -0
- package/dist/config-patchers/index.js +75 -0
- package/dist/config-patchers/types.d.ts +89 -0
- package/dist/config-patchers/types.d.ts.map +1 -0
- package/dist/config-patchers/types.js +25 -0
- package/dist/dockerfile-transformers/core.d.ts +59 -0
- package/dist/dockerfile-transformers/core.d.ts.map +1 -0
- package/dist/dockerfile-transformers/core.js +271 -0
- package/dist/dockerfile-transformers/index.d.ts +42 -0
- package/dist/dockerfile-transformers/index.d.ts.map +1 -0
- package/dist/dockerfile-transformers/index.js +67 -0
- package/dist/dockerfile-transformers/types.d.ts +116 -0
- package/dist/dockerfile-transformers/types.d.ts.map +1 -0
- package/dist/dockerfile-transformers/types.js +29 -0
- package/dist/errors.d.ts +75 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +119 -0
- package/dist/helpers/database.d.ts +54 -0
- package/dist/helpers/database.d.ts.map +1 -0
- package/dist/helpers/database.js +108 -0
- package/dist/helpers/index.d.ts +8 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +6 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/resources/container.d.ts +42 -0
- package/dist/resources/container.d.ts.map +1 -0
- package/dist/resources/container.js +256 -0
- package/dist/resources/image.d.ts +37 -0
- package/dist/resources/image.d.ts.map +1 -0
- package/dist/resources/image.js +113 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +8 -0
- package/dist/resources/network.d.ts +21 -0
- package/dist/resources/network.d.ts.map +1 -0
- package/dist/resources/network.js +86 -0
- package/package.json +28 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile Transformer Core
|
|
3
|
+
*
|
|
4
|
+
* Core parsing, serialization, and pipeline utilities for Dockerfile transformation.
|
|
5
|
+
* This module provides the foundation for all Dockerfile transformers.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect } from 'effect';
|
|
8
|
+
import { TransformerError } from './types';
|
|
9
|
+
// ============ Parsing ============
|
|
10
|
+
/**
|
|
11
|
+
* Parses Dockerfile arguments, handling quoted strings.
|
|
12
|
+
*/
|
|
13
|
+
function parseArgs(argString) {
|
|
14
|
+
const args = [];
|
|
15
|
+
let current = '';
|
|
16
|
+
let inQuotes = false;
|
|
17
|
+
let quoteChar = '';
|
|
18
|
+
for (let i = 0; i < argString.length; i++) {
|
|
19
|
+
const char = argString[i];
|
|
20
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
21
|
+
inQuotes = true;
|
|
22
|
+
quoteChar = char;
|
|
23
|
+
current += char;
|
|
24
|
+
}
|
|
25
|
+
else if (inQuotes && char === quoteChar) {
|
|
26
|
+
inQuotes = false;
|
|
27
|
+
quoteChar = '';
|
|
28
|
+
current += char;
|
|
29
|
+
}
|
|
30
|
+
else if (!inQuotes && char === ' ') {
|
|
31
|
+
if (current.trim()) {
|
|
32
|
+
args.push(current.trim());
|
|
33
|
+
current = '';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
current += char;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (current.trim()) {
|
|
41
|
+
args.push(current.trim());
|
|
42
|
+
}
|
|
43
|
+
return args;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Maps a string to a DockerfileInstruction type.
|
|
47
|
+
*/
|
|
48
|
+
function mapInstructionType(type) {
|
|
49
|
+
const upperType = type.toUpperCase();
|
|
50
|
+
switch (upperType) {
|
|
51
|
+
case 'COPY':
|
|
52
|
+
return 'COPY';
|
|
53
|
+
case 'RUN':
|
|
54
|
+
return 'RUN';
|
|
55
|
+
case 'ENV':
|
|
56
|
+
return 'ENV';
|
|
57
|
+
case 'CMD':
|
|
58
|
+
return 'CMD';
|
|
59
|
+
case 'WORKDIR':
|
|
60
|
+
return 'WORKDIR';
|
|
61
|
+
case 'FROM':
|
|
62
|
+
return 'FROM';
|
|
63
|
+
case 'ARG':
|
|
64
|
+
return 'ARG';
|
|
65
|
+
case 'EXPOSE':
|
|
66
|
+
return 'EXPOSE';
|
|
67
|
+
case 'HEALTHCHECK':
|
|
68
|
+
return 'HEALTHCHECK';
|
|
69
|
+
default:
|
|
70
|
+
return 'OTHER';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parses a Dockerfile into structured instructions.
|
|
75
|
+
* Pure function - synchronous for direct use.
|
|
76
|
+
*
|
|
77
|
+
* @param dockerfile Raw Dockerfile content
|
|
78
|
+
* @returns Array of parsed instructions
|
|
79
|
+
*/
|
|
80
|
+
export function parseDockerfile(dockerfile) {
|
|
81
|
+
const lines = dockerfile.split('\n');
|
|
82
|
+
const instructions = [];
|
|
83
|
+
for (let i = 0; i < lines.length; i++) {
|
|
84
|
+
let line = lines[i];
|
|
85
|
+
if (line === undefined) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Handle line continuations ending with '\'
|
|
89
|
+
while (line.trimEnd().endsWith('\\')) {
|
|
90
|
+
const nextLine = lines[++i];
|
|
91
|
+
if (nextLine === undefined) {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
line = `${line.trimEnd().slice(0, -1)} ${nextLine.trim()}`;
|
|
95
|
+
}
|
|
96
|
+
line = line.trim();
|
|
97
|
+
if (!line || line.startsWith('#')) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const match = line.match(/^(\w+)(?:\s+(.+))?$/);
|
|
101
|
+
if (!match || !match[1]) {
|
|
102
|
+
instructions.push({
|
|
103
|
+
type: 'OTHER',
|
|
104
|
+
args: Object.freeze([]),
|
|
105
|
+
original: line,
|
|
106
|
+
lineNumber: i + 1,
|
|
107
|
+
});
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const type = match[1];
|
|
111
|
+
const rest = match[2];
|
|
112
|
+
const instructionType = mapInstructionType(type);
|
|
113
|
+
const args = rest ? parseArgs(rest) : [];
|
|
114
|
+
instructions.push({
|
|
115
|
+
type: instructionType,
|
|
116
|
+
args: Object.freeze(args),
|
|
117
|
+
original: line,
|
|
118
|
+
lineNumber: i + 1,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return instructions;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Effect-wrapped parser for composable error handling.
|
|
125
|
+
*/
|
|
126
|
+
export function parseDockerfileEffect(dockerfile) {
|
|
127
|
+
return Effect.try({
|
|
128
|
+
try: () => parseDockerfile(dockerfile),
|
|
129
|
+
catch: (error) => new TransformerError('core-parser', `Failed to parse Dockerfile: ${error}`, undefined, error instanceof Error ? error : undefined),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// ============ Serialization ============
|
|
133
|
+
/**
|
|
134
|
+
* Serializes instructions back to Dockerfile format.
|
|
135
|
+
*
|
|
136
|
+
* @param instructions Parsed Dockerfile instructions
|
|
137
|
+
* @returns Dockerfile content as string
|
|
138
|
+
*/
|
|
139
|
+
export function serializeDockerfile(instructions) {
|
|
140
|
+
return instructions.map((inst) => inst.original).join('\n');
|
|
141
|
+
}
|
|
142
|
+
// ============ Pipeline ============
|
|
143
|
+
/**
|
|
144
|
+
* Creates a new transformation pipeline.
|
|
145
|
+
*
|
|
146
|
+
* @param transformers Initial transformers to add
|
|
147
|
+
* @returns A TransformPipeline instance
|
|
148
|
+
*/
|
|
149
|
+
export function createPipeline(transformers = []) {
|
|
150
|
+
const pipelineTransformers = [...transformers];
|
|
151
|
+
const add = (transformer) => {
|
|
152
|
+
pipelineTransformers.push(transformer);
|
|
153
|
+
return pipeline;
|
|
154
|
+
};
|
|
155
|
+
const transform = (dockerfile, ctx) => {
|
|
156
|
+
return Effect.gen(function* () {
|
|
157
|
+
// Parse Dockerfile
|
|
158
|
+
const instructions = yield* parseDockerfileEffect(dockerfile);
|
|
159
|
+
// Track current stage for context
|
|
160
|
+
let currentStage;
|
|
161
|
+
const transformedInstructions = [];
|
|
162
|
+
for (const inst of instructions) {
|
|
163
|
+
// Track stage transitions
|
|
164
|
+
if (inst.type === 'FROM' &&
|
|
165
|
+
inst.original.toLowerCase().includes(' as ')) {
|
|
166
|
+
const stageMatch = inst.original.match(/\s+as\s+(\w+)/i);
|
|
167
|
+
if (stageMatch) {
|
|
168
|
+
currentStage = stageMatch[1];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Create context with current stage
|
|
172
|
+
const instCtx = currentStage
|
|
173
|
+
? { ...ctx, currentStage }
|
|
174
|
+
: ctx;
|
|
175
|
+
// Apply matching transformers
|
|
176
|
+
let current = [inst];
|
|
177
|
+
for (const transformer of pipelineTransformers) {
|
|
178
|
+
const next = [];
|
|
179
|
+
for (const currentInst of current) {
|
|
180
|
+
// Check if transformer handles this instruction type
|
|
181
|
+
if (!transformer.handlesTypes.includes(currentInst.type)) {
|
|
182
|
+
next.push(currentInst);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// Check if transformer matches this instruction
|
|
186
|
+
if (!transformer.matches(currentInst, instCtx)) {
|
|
187
|
+
next.push(currentInst);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Apply transformation
|
|
191
|
+
const result = transformer.transform(currentInst, instCtx);
|
|
192
|
+
// Check if result is an array (has 'type' means it's a single instruction)
|
|
193
|
+
if ('type' in result && typeof result.type === 'string') {
|
|
194
|
+
next.push(result);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
for (const r of result) {
|
|
198
|
+
next.push(r);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
current = next;
|
|
203
|
+
}
|
|
204
|
+
transformedInstructions.push(...current);
|
|
205
|
+
}
|
|
206
|
+
return serializeDockerfile(transformedInstructions);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
const pipeline = {
|
|
210
|
+
add,
|
|
211
|
+
transform,
|
|
212
|
+
get transformers() {
|
|
213
|
+
return Object.freeze([...pipelineTransformers]);
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
return pipeline;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Transform a Dockerfile using a pipeline and return full result.
|
|
220
|
+
*/
|
|
221
|
+
export function transformDockerfile(dockerfile, ctx, pipeline) {
|
|
222
|
+
return Effect.gen(function* () {
|
|
223
|
+
const transformedDockerfile = yield* pipeline.transform(dockerfile, ctx);
|
|
224
|
+
return {
|
|
225
|
+
transformedDockerfile,
|
|
226
|
+
context: ctx,
|
|
227
|
+
appliedTransformers: pipeline.transformers.map((t) => t.name),
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// ============ Utility Functions ============
|
|
232
|
+
/**
|
|
233
|
+
* Creates a simple instruction that replaces the original line.
|
|
234
|
+
*/
|
|
235
|
+
export function replaceInstruction(inst, newOriginal, newArgs) {
|
|
236
|
+
return {
|
|
237
|
+
...inst,
|
|
238
|
+
original: newOriginal,
|
|
239
|
+
args: newArgs ? Object.freeze([...newArgs]) : inst.args,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Creates multiple instructions from one (for splitting).
|
|
244
|
+
*/
|
|
245
|
+
export function splitInstruction(inst, replacements) {
|
|
246
|
+
return replacements.map((r) => ({
|
|
247
|
+
type: inst.type,
|
|
248
|
+
args: r.args ? Object.freeze([...r.args]) : Object.freeze([]),
|
|
249
|
+
original: r.original,
|
|
250
|
+
lineNumber: inst.lineNumber,
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check if an instruction's args contain a pattern.
|
|
255
|
+
*/
|
|
256
|
+
export function argsContain(inst, pattern) {
|
|
257
|
+
return inst.args.some((arg) => {
|
|
258
|
+
if (!arg)
|
|
259
|
+
return false;
|
|
260
|
+
if (typeof pattern === 'string') {
|
|
261
|
+
return arg.includes(pattern);
|
|
262
|
+
}
|
|
263
|
+
return pattern.test(arg);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get a specific argument by index (0-based).
|
|
268
|
+
*/
|
|
269
|
+
export function getArg(inst, index) {
|
|
270
|
+
return inst.args[index];
|
|
271
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile Transformers Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for Dockerfile instruction transformers.
|
|
5
|
+
* Provides pipeline building and transformer lookup.
|
|
6
|
+
*
|
|
7
|
+
* Note: Tool-specific transformers (Prisma, Next.js, etc.) are provided
|
|
8
|
+
* by their respective binding packages (@harpoon/prisma, @harpoon/nextjs, etc.)
|
|
9
|
+
*/
|
|
10
|
+
import type { InstructionTransformer, TransformerRegistry, TransformPipeline, DockerfileInstruction } from './types';
|
|
11
|
+
export { TransformerError } from './types';
|
|
12
|
+
export type { InstructionTransformer, DockerfileInstruction, TransformContext, TransformerRegistry, TransformPipeline, TransformResult, } from './types';
|
|
13
|
+
export { parseDockerfile, parseDockerfileEffect, serializeDockerfile, createPipeline, transformDockerfile, replaceInstruction, splitInstruction, argsContain, getArg, } from './core';
|
|
14
|
+
/**
|
|
15
|
+
* Transformer registry singleton.
|
|
16
|
+
*/
|
|
17
|
+
export declare const transformerRegistry: TransformerRegistry;
|
|
18
|
+
/**
|
|
19
|
+
* Register an instruction transformer.
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerTransformer(transformer: InstructionTransformer): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get a transformer by name.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTransformer(name: string): InstructionTransformer | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* List all registered transformer names.
|
|
28
|
+
*/
|
|
29
|
+
export declare function listTransformers(): readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Get all transformers that handle a specific instruction type.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getTransformersForType(type: DockerfileInstruction['type']): readonly InstructionTransformer[];
|
|
34
|
+
/**
|
|
35
|
+
* Create a pipeline with all registered transformers.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createDefaultPipeline(): TransformPipeline;
|
|
38
|
+
/**
|
|
39
|
+
* Create a pipeline with specific transformers by name.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createPipelineWithTransformers(names: readonly string[]): TransformPipeline;
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dockerfile-transformers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,MAAM,GACP,MAAM,QAAQ,CAAC;AAMhB;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,mBAajC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAE7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX,sBAAsB,GAAG,SAAS,CAEpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,MAAM,EAAE,CAEpD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC,GAClC,SAAS,sBAAsB,EAAE,CAEnC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,CAGzD;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,iBAAiB,CAMnB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile Transformers Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for Dockerfile instruction transformers.
|
|
5
|
+
* Provides pipeline building and transformer lookup.
|
|
6
|
+
*
|
|
7
|
+
* Note: Tool-specific transformers (Prisma, Next.js, etc.) are provided
|
|
8
|
+
* by their respective binding packages (@harpoon/prisma, @harpoon/nextjs, etc.)
|
|
9
|
+
*/
|
|
10
|
+
// Re-export types
|
|
11
|
+
export { TransformerError } from './types';
|
|
12
|
+
// Re-export core utilities
|
|
13
|
+
export { parseDockerfile, parseDockerfileEffect, serializeDockerfile, createPipeline, transformDockerfile, replaceInstruction, splitInstruction, argsContain, getArg, } from './core';
|
|
14
|
+
// ============ Registry Implementation ============
|
|
15
|
+
const transformers = new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Transformer registry singleton.
|
|
18
|
+
*/
|
|
19
|
+
export const transformerRegistry = {
|
|
20
|
+
get: (name) => transformers.get(name),
|
|
21
|
+
register: (transformer) => {
|
|
22
|
+
transformers.set(transformer.name, transformer);
|
|
23
|
+
},
|
|
24
|
+
list: () => Object.freeze([...transformers.keys()]),
|
|
25
|
+
getForType: (type) => Object.freeze([...transformers.values()].filter((t) => t.handlesTypes.includes(type))),
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Register an instruction transformer.
|
|
29
|
+
*/
|
|
30
|
+
export function registerTransformer(transformer) {
|
|
31
|
+
transformerRegistry.register(transformer);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get a transformer by name.
|
|
35
|
+
*/
|
|
36
|
+
export function getTransformer(name) {
|
|
37
|
+
return transformerRegistry.get(name);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* List all registered transformer names.
|
|
41
|
+
*/
|
|
42
|
+
export function listTransformers() {
|
|
43
|
+
return transformerRegistry.list();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get all transformers that handle a specific instruction type.
|
|
47
|
+
*/
|
|
48
|
+
export function getTransformersForType(type) {
|
|
49
|
+
return transformerRegistry.getForType(type);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a pipeline with all registered transformers.
|
|
53
|
+
*/
|
|
54
|
+
export function createDefaultPipeline() {
|
|
55
|
+
const { createPipeline } = require('./core');
|
|
56
|
+
return createPipeline([...transformers.values()]);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a pipeline with specific transformers by name.
|
|
60
|
+
*/
|
|
61
|
+
export function createPipelineWithTransformers(names) {
|
|
62
|
+
const { createPipeline } = require('./core');
|
|
63
|
+
const selected = names
|
|
64
|
+
.map((name) => transformers.get(name))
|
|
65
|
+
.filter((t) => t !== undefined);
|
|
66
|
+
return createPipeline(selected);
|
|
67
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile Transformer Types
|
|
3
|
+
*
|
|
4
|
+
* Interfaces for composable Dockerfile instruction transformers.
|
|
5
|
+
* Transformers modify individual Dockerfile instructions.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect } from 'effect';
|
|
8
|
+
/**
|
|
9
|
+
* Parsed Dockerfile instruction.
|
|
10
|
+
*/
|
|
11
|
+
export interface DockerfileInstruction {
|
|
12
|
+
readonly type: 'COPY' | 'RUN' | 'ENV' | 'CMD' | 'WORKDIR' | 'FROM' | 'ARG' | 'EXPOSE' | 'HEALTHCHECK' | 'OTHER';
|
|
13
|
+
readonly args: readonly (string | undefined)[];
|
|
14
|
+
readonly original: string;
|
|
15
|
+
readonly lineNumber: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Context provided during Dockerfile transformation.
|
|
19
|
+
*/
|
|
20
|
+
export interface TransformContext {
|
|
21
|
+
/** Name of the app being built */
|
|
22
|
+
readonly appName: string;
|
|
23
|
+
/** Folders copied to the build context */
|
|
24
|
+
readonly copiedFolders: readonly string[];
|
|
25
|
+
/** Root files copied to the build context */
|
|
26
|
+
readonly copiedRootFiles: readonly string[];
|
|
27
|
+
/** Source directory for shared folders */
|
|
28
|
+
readonly sharedSource: string;
|
|
29
|
+
/** Temp directory for build context */
|
|
30
|
+
readonly tempDir: string;
|
|
31
|
+
/** Whether this is a standalone app (vs already monorepo) */
|
|
32
|
+
readonly isStandaloneApp?: boolean;
|
|
33
|
+
/** Current stage name (e.g., 'builder', 'runner') */
|
|
34
|
+
readonly currentStage?: string;
|
|
35
|
+
/** Additional metadata */
|
|
36
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Error during Dockerfile transformation.
|
|
40
|
+
*/
|
|
41
|
+
export declare class TransformerError extends Error {
|
|
42
|
+
readonly _tag: "TransformerError";
|
|
43
|
+
readonly transformerName: string;
|
|
44
|
+
readonly instruction?: DockerfileInstruction | undefined;
|
|
45
|
+
readonly cause?: Error | undefined;
|
|
46
|
+
constructor(transformerName: string, message: string, instruction?: DockerfileInstruction, cause?: Error);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A single Dockerfile instruction transformer.
|
|
50
|
+
*
|
|
51
|
+
* Transformers are applied to individual instructions and can:
|
|
52
|
+
* - Return the instruction unchanged
|
|
53
|
+
* - Return a modified instruction
|
|
54
|
+
* - Return multiple instructions (splitting)
|
|
55
|
+
* - Return an empty array (removing the instruction)
|
|
56
|
+
*/
|
|
57
|
+
export interface InstructionTransformer {
|
|
58
|
+
/** Unique transformer identifier */
|
|
59
|
+
readonly name: string;
|
|
60
|
+
/** Human-readable description */
|
|
61
|
+
readonly description: string;
|
|
62
|
+
/** Instruction types this transformer handles */
|
|
63
|
+
readonly handlesTypes: readonly DockerfileInstruction['type'][];
|
|
64
|
+
/**
|
|
65
|
+
* Check if this transformer should process the instruction.
|
|
66
|
+
*
|
|
67
|
+
* @param inst The Dockerfile instruction
|
|
68
|
+
* @param ctx Transform context
|
|
69
|
+
* @returns true if transformer should handle this instruction
|
|
70
|
+
*/
|
|
71
|
+
readonly matches: (inst: DockerfileInstruction, ctx: TransformContext) => boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Transform the instruction.
|
|
74
|
+
*
|
|
75
|
+
* @param inst The Dockerfile instruction
|
|
76
|
+
* @param ctx Transform context
|
|
77
|
+
* @returns Transformed instruction(s) or empty array to remove
|
|
78
|
+
*/
|
|
79
|
+
readonly transform: (inst: DockerfileInstruction, ctx: TransformContext) => DockerfileInstruction | readonly DockerfileInstruction[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Registry of instruction transformers.
|
|
83
|
+
*/
|
|
84
|
+
export interface TransformerRegistry {
|
|
85
|
+
/** Get a transformer by name */
|
|
86
|
+
readonly get: (name: string) => InstructionTransformer | undefined;
|
|
87
|
+
/** Register a new transformer */
|
|
88
|
+
readonly register: (transformer: InstructionTransformer) => void;
|
|
89
|
+
/** List all registered transformer names */
|
|
90
|
+
readonly list: () => readonly string[];
|
|
91
|
+
/** Get transformers that handle a specific instruction type */
|
|
92
|
+
readonly getForType: (type: DockerfileInstruction['type']) => readonly InstructionTransformer[];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A transformation pipeline that applies multiple transformers.
|
|
96
|
+
*/
|
|
97
|
+
export interface TransformPipeline {
|
|
98
|
+
/** Add a transformer to the pipeline */
|
|
99
|
+
readonly add: (transformer: InstructionTransformer) => TransformPipeline;
|
|
100
|
+
/** Transform an entire Dockerfile */
|
|
101
|
+
readonly transform: (dockerfile: string, ctx: TransformContext) => Effect.Effect<string, TransformerError>;
|
|
102
|
+
/** Get all transformers in the pipeline */
|
|
103
|
+
readonly transformers: readonly InstructionTransformer[];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Result of transforming a Dockerfile.
|
|
107
|
+
*/
|
|
108
|
+
export interface TransformResult {
|
|
109
|
+
/** The transformed Dockerfile content */
|
|
110
|
+
readonly transformedDockerfile: string;
|
|
111
|
+
/** Context used for transformation */
|
|
112
|
+
readonly context: TransformContext;
|
|
113
|
+
/** Transformers that were applied */
|
|
114
|
+
readonly appliedTransformers: readonly string[];
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dockerfile-transformers/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile Transformer Types
|
|
3
|
+
*
|
|
4
|
+
* Interfaces for composable Dockerfile instruction transformers.
|
|
5
|
+
* Transformers modify individual Dockerfile instructions.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error during Dockerfile transformation.
|
|
9
|
+
*/
|
|
10
|
+
export class TransformerError extends Error {
|
|
11
|
+
_tag = 'TransformerError';
|
|
12
|
+
transformerName;
|
|
13
|
+
instruction;
|
|
14
|
+
cause;
|
|
15
|
+
constructor(transformerName, message, instruction, cause) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'TransformerError';
|
|
18
|
+
this.transformerName = transformerName;
|
|
19
|
+
if (instruction) {
|
|
20
|
+
this.instruction = instruction;
|
|
21
|
+
}
|
|
22
|
+
if (cause) {
|
|
23
|
+
this.cause = cause;
|
|
24
|
+
}
|
|
25
|
+
if (Error.captureStackTrace) {
|
|
26
|
+
Error.captureStackTrace(this, this.constructor);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harpoon Core Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Typed error classes for Docker resource operations.
|
|
5
|
+
* Provides clear error categorization.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Base error class for all Harpoon errors.
|
|
9
|
+
*/
|
|
10
|
+
export declare class HarpoonError extends Error {
|
|
11
|
+
/** Effect integration discriminant */
|
|
12
|
+
readonly _tag: string;
|
|
13
|
+
/** Resource identifier that caused the error */
|
|
14
|
+
readonly resource: string;
|
|
15
|
+
/** Original error that caused this error */
|
|
16
|
+
readonly cause?: Error;
|
|
17
|
+
constructor(message: string, resource: string, cause?: Error);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error during network operations.
|
|
21
|
+
*/
|
|
22
|
+
export declare class NetworkError extends HarpoonError {
|
|
23
|
+
readonly _tag: 'NetworkError';
|
|
24
|
+
constructor(name: string, message?: string, cause?: Error);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error during image build operations.
|
|
28
|
+
*/
|
|
29
|
+
export declare class ImageError extends HarpoonError {
|
|
30
|
+
readonly _tag: 'ImageError';
|
|
31
|
+
constructor(tag: string, message?: string, cause?: Error);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Error during container operations.
|
|
35
|
+
*/
|
|
36
|
+
export declare class ContainerError extends HarpoonError {
|
|
37
|
+
readonly _tag: 'ContainerError';
|
|
38
|
+
constructor(name: string, message?: string, cause?: Error);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Error during scope operations.
|
|
42
|
+
*/
|
|
43
|
+
export declare class ScopeError extends HarpoonError {
|
|
44
|
+
readonly _tag: 'ScopeError';
|
|
45
|
+
constructor(message: string, cause?: Error);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Error during binding operations.
|
|
49
|
+
*/
|
|
50
|
+
export declare class BindingError extends HarpoonError {
|
|
51
|
+
readonly _tag: 'BindingError';
|
|
52
|
+
readonly bindingType: string;
|
|
53
|
+
constructor(bindingType: string, message: string, cause?: Error);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Convert an unknown error to an Error instance for use as cause.
|
|
57
|
+
* Preserves Error instances, wraps non-Errors in new Error.
|
|
58
|
+
*/
|
|
59
|
+
export declare function asCause(error: unknown): Error;
|
|
60
|
+
/**
|
|
61
|
+
* Transform an unknown error into a typed HarpoonError.
|
|
62
|
+
*/
|
|
63
|
+
export declare function toHarpoonError(error: unknown, resource: string, ErrorClass?: typeof HarpoonError): HarpoonError;
|
|
64
|
+
/**
|
|
65
|
+
* Union type of all API-facing error classes.
|
|
66
|
+
* Useful for Effect error channel typing.
|
|
67
|
+
*/
|
|
68
|
+
export type HarpoonApiError = NetworkError | ImageError | ContainerError | ScopeError | BindingError;
|
|
69
|
+
export declare const isHarpoonError: (e: unknown) => e is HarpoonError;
|
|
70
|
+
export declare const isNetworkError: (e: unknown) => e is NetworkError;
|
|
71
|
+
export declare const isImageError: (e: unknown) => e is ImageError;
|
|
72
|
+
export declare const isContainerError: (e: unknown) => e is ContainerError;
|
|
73
|
+
export declare const isScopeError: (e: unknown) => e is ScopeError;
|
|
74
|
+
export declare const isBindingError: (e: unknown) => e is BindingError;
|
|
75
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAkB;IAEvC,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAY7D;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,SAAkB,IAAI,EAAE,cAAc,CAAkB;gBAE5C,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAQ1D;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,SAAkB,IAAI,EAAE,YAAY,CAAgB;gBAExC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAQzD;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,SAAkB,IAAI,EAAE,gBAAgB,CAAoB;gBAEhD,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAQ1D;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,SAAkB,IAAI,EAAE,YAAY,CAAgB;gBAExC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAI3C;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,SAAkB,IAAI,EAAE,cAAc,CAAkB;IAExD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAKhE;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,OAAO,YAA2B,GAC7C,YAAY,CA4Bd;AAID;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,UAAU,GACV,cAAc,GACd,UAAU,GACV,YAAY,CAAC;AAIjB,eAAO,MAAM,cAAc,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,YACtB,CAAC;AAE5B,eAAO,MAAM,cAAc,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,YACtB,CAAC;AAE5B,eAAO,MAAM,YAAY,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,UACtB,CAAC;AAE1B,eAAO,MAAM,gBAAgB,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,cACtB,CAAC;AAE9B,eAAO,MAAM,YAAY,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,UACtB,CAAC;AAE1B,eAAO,MAAM,cAAc,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,YACtB,CAAC"}
|