or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bundle-building.mdcomposition.mdconsumption.mdfunction-maps.mdgeneration.mdindex.mdutilities.md

composition.mddocs/

0

# Source Map Composition

1

2

Functionality for composing multiple source maps into a single source map, essential for multi-stage transformations in modern JavaScript toolchains.

3

4

## Capabilities

5

6

### Source Map Composition

7

8

Combine multiple source maps from a transformation pipeline into a single composite source map that maps directly from the final output back to the original source.

9

10

```javascript { .api }

11

/**

12

* Composes multiple source maps into a single source map

13

* Useful for multi-stage transformations where each stage produces its own source map

14

* @param maps - Array of source maps to compose, in transformation order

15

* @returns Single composed source map mapping final output to original sources

16

*/

17

function composeSourceMaps(maps: Array<MixedSourceMap>): MixedSourceMap;

18

```

19

20

**Usage Examples:**

21

22

```javascript

23

const { composeSourceMaps } = require("metro-source-map");

24

25

// Example: TypeScript -> Babel -> Minifier transformation pipeline

26

const typeScriptMap = {

27

version: 3,

28

sources: ["src/app.ts"],

29

names: ["greeting"],

30

mappings: "AAAA,MAAM,QAAQ,GAAW,YAAY,CAAC",

31

sourcesContent: ["const greeting: string = 'hello';"]

32

};

33

34

const babelMap = {

35

version: 3,

36

sources: ["intermediate.js"],

37

names: ["greeting"],

38

mappings: "AAAA,IAAM,QAAQ,GAAG,YAAY,CAAC",

39

sourcesContent: ["var greeting = 'hello';"]

40

};

41

42

const minifierMap = {

43

version: 3,

44

sources: ["babel-output.js"],

45

names: ["a"],

46

mappings: "AAAA,IAAM,CAAC,CAAC,CAAC",

47

sourcesContent: ["var a='hello';"]

48

};

49

50

// Compose all transformations into a single map

51

// Final minified output -> Original TypeScript source

52

const composedMap = composeSourceMaps([

53

typeScriptMap, // TS -> JS

54

babelMap, // JS -> Babel JS

55

minifierMap // Babel JS -> Minified

56

]);

57

58

// The composed map now maps directly from minified code to original TypeScript

59

console.log(composedMap.sources); // ["src/app.ts"]

60

console.log(composedMap.sourcesContent[0]); // "const greeting: string = 'hello';"

61

```

62

63

### Multi-Stage Transformation

64

65

```javascript

66

const { composeSourceMaps, Generator } = require("metro-source-map");

67

68

// Example: Building a complex transformation pipeline

69

function createTransformationPipeline(originalCode, stages) {

70

const sourceMaps = [];

71

let currentCode = originalCode;

72

73

// Apply each transformation stage

74

stages.forEach((transform, index) => {

75

const result = transform(currentCode);

76

currentCode = result.code;

77

sourceMaps.push(result.map);

78

});

79

80

// Compose all source maps into one

81

const finalMap = composeSourceMaps(sourceMaps);

82

83

return {

84

code: currentCode,

85

map: finalMap

86

};

87

}

88

89

// Usage

90

const pipeline = createTransformationPipeline(originalTypeScript, [

91

typeScriptTransform,

92

babelTransform,

93

minifyTransform

94

]);

95

96

console.log(pipeline.code); // Final transformed code

97

console.log(pipeline.map.sources[0]); // Original source file

98

```

99

100

### Working with Different Source Map Types

101

102

```javascript

103

const { composeSourceMaps } = require("metro-source-map");

104

105

// Compose basic and indexed source maps

106

const basicMap1 = {

107

version: 3,

108

sources: ["input.js"],

109

names: ["fn"],

110

mappings: "AAAA,SAAS,EAAE"

111

};

112

113

const indexedMap = {

114

version: 3,

115

sections: [

116

{

117

offset: { line: 0, column: 0 },

118

map: {

119

version: 3,

120

sources: ["module1.js"],

121

names: ["helper"],

122

mappings: "AAAA,SAAS,MAAM"

123

}

124

}

125

]

126

};

127

128

const basicMap2 = {

129

version: 3,

130

sources: ["transformed.js"],

131

names: ["final"],

132

mappings: "AAAA,QAAQ,KAAK"

133

};

134

135

// Compose mixed source map types

136

const composed = composeSourceMaps([basicMap1, indexedMap, basicMap2]);

137

// Result will be a source map that traces back to the original sources

138

```

139

140

### Facebook and Hermes Extensions

141

142

The composition function preserves Facebook-specific and Hermes-specific extensions when composing source maps.

143

144

```javascript

145

const { composeSourceMaps } = require("metro-source-map");

146

147

// Source maps with Facebook extensions

148

const mapWithExtensions = {

149

version: 3,

150

sources: ["app.js"],

151

names: ["main"],

152

mappings: "AAAA",

153

x_facebook_sources: [

154

[{

155

names: ["functionA", "functionB"],

156

mappings: "AAAA,CAAC"

157

}]

158

],

159

x_hermes_function_offsets: {

160

0: [10, 20, 30]

161

},

162

x_metro_module_paths: ["src/app.js"]

163

};

164

165

const regularMap = {

166

version: 3,

167

sources: ["transformed.js"],

168

names: ["transformed"],

169

mappings: "AAAA"

170

};

171

172

// Compose maps preserving extensions

173

const composedWithExtensions = composeSourceMaps([

174

mapWithExtensions,

175

regularMap

176

]);

177

178

// Facebook/Hermes extensions are preserved in the result

179

console.log(composedWithExtensions.x_facebook_sources);

180

console.log(composedWithExtensions.x_hermes_function_offsets);

181

```

182

183

### Integration with Bundle Building

184

185

```javascript

186

const { composeSourceMaps, BundleBuilder } = require("metro-source-map");

187

188

// Use composition in bundle building workflows

189

function buildBundleWithComposition(modules) {

190

const builder = new BundleBuilder("bundle.js");

191

192

modules.forEach(module => {

193

// Each module might have its own transformation chain

194

const composedMap = composeSourceMaps(module.transformationMaps);

195

builder.append(module.code, composedMap);

196

});

197

198

return {

199

code: builder.getCode(),

200

map: builder.getMap()

201

};

202

}

203

204

// Usage

205

const bundle = buildBundleWithComposition([

206

{

207

code: "var utils = require('./utils');",

208

transformationMaps: [tsToJsMap, babelMap]

209

},

210

{

211

code: "var app = require('./app');",

212

transformationMaps: [tsToJsMap, babelMap, minifyMap]

213

}

214

]);

215

```

216

217

## Error Handling

218

219

Source map composition may encounter errors in the following cases:

220

221

- **Invalid source maps**: When input source maps are malformed or have invalid structure

222

- **Empty input**: When the maps array is empty or contains null/undefined values

223

- **Circular references**: When source maps reference each other in circular patterns

224

225

```javascript

226

const { composeSourceMaps } = require("metro-source-map");

227

228

try {

229

const composed = composeSourceMaps([validMap1, validMap2]);

230

} catch (error) {

231

if (error.message.includes('Invalid source map')) {

232

console.error('One of the input source maps is malformed:', error);

233

} else {

234

console.error('Source map composition failed:', error);

235

}

236

}

237

238

// Safe composition with validation

239

function safeComposeSourceMaps(maps) {

240

const validMaps = maps.filter(map =>

241

map && typeof map === 'object' && map.version === 3

242

);

243

244

if (validMaps.length === 0) {

245

return null;

246

}

247

248

if (validMaps.length === 1) {

249

return validMaps[0];

250

}

251

252

return composeSourceMaps(validMaps);

253

}

254

```