or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-analysis.mdcode-generation.mdfile-processing.mdindex.mdregex-utilities.md

code-generation.mddocs/

0

# Code Generation

1

2

Utilities for generating valid JavaScript code, identifiers, and ES modules from data structures. These functions help create bundle-safe code and transform data into tree-shakable modules.

3

4

## Capabilities

5

6

### makeLegalIdentifier

7

8

Converts strings into valid JavaScript identifiers that are safe for use in bundles. Handles special characters, reserved words, and naming conflicts.

9

10

```typescript { .api }

11

/**

12

* Constructs a bundle-safe identifier from a string

13

* Converts invalid characters and handles reserved words

14

* @param str - The string to convert to a legal identifier

15

* @returns A valid JavaScript identifier

16

*/

17

function makeLegalIdentifier(str: string): string;

18

```

19

20

**Parameters:**

21

22

- `str` (string): The string to convert to a legal JavaScript identifier

23

24

**Returns:** A valid JavaScript identifier string

25

26

**Transformation Rules:**

27

28

- Converts hyphens to camelCase: `'foo-bar'``'fooBar'`

29

- Replaces invalid characters with underscores

30

- Prefixes with underscore if starts with number: `'123abc'``'_123abc'`

31

- Handles reserved words: `'typeof'``'_typeof'`

32

- Returns `'_'` for empty strings

33

34

**Usage Examples:**

35

36

```typescript

37

import { makeLegalIdentifier } from "@rollup/pluginutils";

38

39

// Basic transformations

40

makeLegalIdentifier('foo-bar'); // 'fooBar'

41

makeLegalIdentifier('my-component'); // 'myComponent'

42

makeLegalIdentifier('foo_bar'); // 'foo_bar' (already valid)

43

44

// Handle special characters

45

makeLegalIdentifier('foo@bar'); // 'foo_bar'

46

makeLegalIdentifier('foo.bar'); // 'foo_bar'

47

makeLegalIdentifier('foo bar'); // 'foo_bar'

48

49

// Reserved words and edge cases

50

makeLegalIdentifier('typeof'); // '_typeof'

51

makeLegalIdentifier('class'); // '_class'

52

makeLegalIdentifier('123abc'); // '_123abc'

53

makeLegalIdentifier(''); // '_'

54

55

// Use in code generation

56

export default function myPlugin() {

57

return {

58

generateBundle(options, bundle) {

59

for (const [fileName, chunk] of Object.entries(bundle)) {

60

if (chunk.type === 'chunk') {

61

// Generate safe variable names from file names

62

const varName = makeLegalIdentifier(

63

fileName.replace(/\.[^.]+$/, '') // remove extension

64

);

65

66

// Use in generated code

67

const wrapper = `

68

const ${varName} = (function() {

69

${chunk.code}

70

return exports;

71

})();

72

`;

73

74

chunk.code = wrapper;

75

}

76

}

77

}

78

};

79

}

80

81

// Generate imports from module names

82

function generateImportName(moduleName) {

83

// Convert scoped packages: '@rollup/plugin-utils' → 'rollupPluginUtils'

84

const cleaned = moduleName.replace(/^@/, '').replace(/[^\w]/g, '-');

85

return makeLegalIdentifier(cleaned);

86

}

87

88

generateImportName('@rollup/plugin-utils'); // 'rollupPluginUtils'

89

generateImportName('lodash-es'); // 'lodashEs'

90

generateImportName('my-library/sub-module'); // 'myLibrarySubModule'

91

```

92

93

### dataToEsm

94

95

Transforms JavaScript objects into tree-shakable ES module source code. Generates both named exports and default exports with comprehensive formatting options.

96

97

```typescript { .api }

98

/**

99

* Transforms objects into tree-shakable ES Module imports

100

* Generates both named and default exports with formatting options

101

* @param data - An object to transform into an ES module

102

* @param options - Configuration options for code generation

103

* @returns Generated ES module source code

104

*/

105

function dataToEsm(data: unknown, options?: DataToEsmOptions): string;

106

107

interface DataToEsmOptions {

108

compact?: boolean;

109

includeArbitraryNames?: boolean;

110

indent?: string;

111

namedExports?: boolean;

112

objectShorthand?: boolean;

113

preferConst?: boolean;

114

}

115

```

116

117

**Parameters:**

118

119

- `data` (unknown): The data to convert to ES module format

120

- `options` (DataToEsmOptions, optional): Configuration options

121

122

**DataToEsmOptions:**

123

124

- `compact?: boolean` - Minimize whitespace in generated code (default: `false`)

125

- `includeArbitraryNames?: boolean` - Support non-identifier keys as named exports using arbitrary module namespace identifier names (default: `false`)

126

- `indent?: string` - Indentation string for formatting (default: `'\t'`)

127

- `namedExports?: boolean` - Generate named exports for object properties (default: `true`)

128

- `objectShorthand?: boolean` - Use ES6 object property shorthand syntax (default: `true`)

129

- `preferConst?: boolean` - Use `const` instead of `var` for declarations (default: `false`)

130

131

**Returns:** Generated ES module source code as a string

132

133

**Supported Data Types:**

134

135

- Objects with property values

136

- Arrays with numeric indices

137

- Primitive values (string, number, boolean)

138

- Special values (Date, RegExp, BigInt, Symbol, Infinity, NaN, undefined)

139

- Nested structures

140

141

**Usage Examples:**

142

143

```typescript

144

import { dataToEsm } from "@rollup/pluginutils";

145

146

// Basic object transformation

147

const config = {

148

apiUrl: 'https://api.example.com',

149

timeout: 5000,

150

debug: true

151

};

152

153

const moduleCode = dataToEsm(config, {

154

compact: false,

155

indent: ' ',

156

preferConst: true,

157

objectShorthand: true,

158

namedExports: true

159

});

160

161

console.log(moduleCode);

162

/*

163

export const apiUrl = 'https://api.example.com';

164

export const timeout = 5000;

165

export const debug = true;

166

export default { apiUrl, timeout, debug };

167

*/

168

169

// Complex data with formatting options

170

const complexData = {

171

users: ['alice', 'bob'],

172

settings: {

173

theme: 'dark',

174

notifications: true

175

},

176

created: new Date('2023-01-01'),

177

pattern: /^\w+$/,

178

bigNumber: BigInt('9007199254740991')

179

};

180

181

const compactCode = dataToEsm(complexData, {

182

compact: true,

183

namedExports: true,

184

includeArbitraryNames: false

185

});

186

187

// Use in plugin for configuration files

188

export default function configPlugin(options = {}) {

189

return {

190

resolveId(id) {

191

if (id === 'virtual:config') {

192

return id;

193

}

194

},

195

196

load(id) {

197

if (id === 'virtual:config') {

198

// Convert plugin options to ES module

199

return dataToEsm(options, {

200

preferConst: true,

201

objectShorthand: true,

202

namedExports: true

203

});

204

}

205

}

206

};

207

}

208

209

// Handle non-identifier keys

210

const dataWithSpecialKeys = {

211

'normal-key': 'value1',

212

'special@key': 'value2',

213

'123numeric': 'value3'

214

};

215

216

const codeWithArbitraryNames = dataToEsm(dataWithSpecialKeys, {

217

includeArbitraryNames: true,

218

namedExports: true

219

});

220

221

/*

222

export const normalKey = 'value1';

223

export { 'special@key' as specialKey };

224

export { '123numeric' as _123numeric };

225

export default { normalKey, 'special@key': specialKey, '123numeric': _123numeric };

226

*/

227

228

// Generate module from JSON file

229

export default function jsonPlugin() {

230

return {

231

transform(code, id) {

232

if (id.endsWith('.json')) {

233

const data = JSON.parse(code);

234

235

// Convert JSON to tree-shakable ES module

236

const esModule = dataToEsm(data, {

237

preferConst: true,

238

namedExports: true,

239

objectShorthand: true

240

});

241

242

return { code: esModule };

243

}

244

}

245

};

246

}

247

```

248

249

## Common Patterns

250

251

### Configuration Module Generation

252

253

```typescript

254

import { dataToEsm, makeLegalIdentifier } from "@rollup/pluginutils";

255

256

export default function configPlugin(userConfig = {}) {

257

const defaultConfig = {

258

apiEndpoint: 'https://api.example.com',

259

timeout: 5000,

260

retries: 3,

261

debug: false

262

};

263

264

const finalConfig = { ...defaultConfig, ...userConfig };

265

266

return {

267

resolveId(id) {

268

if (id === 'virtual:app-config') return id;

269

},

270

271

load(id) {

272

if (id === 'virtual:app-config') {

273

// Generate tree-shakable config module

274

return dataToEsm(finalConfig, {

275

preferConst: true,

276

namedExports: true,

277

objectShorthand: true,

278

compact: false

279

});

280

}

281

}

282

};

283

}

284

285

// Usage in application code:

286

// import { apiEndpoint, timeout } from 'virtual:app-config';

287

```

288

289

### Dynamic Import Generation

290

291

```typescript

292

import { makeLegalIdentifier, dataToEsm } from "@rollup/pluginutils";

293

294

export default function dynamicImportPlugin(options = {}) {

295

const { modules = {} } = options;

296

297

return {

298

generateBundle() {

299

// Generate loader module with dynamic imports

300

const loaderCode = Object.entries(modules)

301

.map(([key, modulePath]) => {

302

const importName = makeLegalIdentifier(key);

303

return `

304

export const ${importName} = () => import('${modulePath}');

305

`.trim();

306

})

307

.join('\n');

308

309

// Also generate static config

310

const configModule = dataToEsm({

311

availableModules: Object.keys(modules),

312

moduleCount: Object.keys(modules).length

313

});

314

315

this.emitFile({

316

type: 'asset',

317

fileName: 'dynamic-loader.js',

318

source: loaderCode

319

});

320

321

this.emitFile({

322

type: 'asset',

323

fileName: 'loader-config.js',

324

source: configModule

325

});

326

}

327

};

328

}

329

```

330

331

### Safe Variable Generation

332

333

```typescript

334

import { makeLegalIdentifier } from "@rollup/pluginutils";

335

336

export default function namespacePlugin(options = {}) {

337

const { namespace = 'MyLibrary' } = options;

338

339

return {

340

generateBundle(options, bundle) {

341

for (const [fileName, chunk] of Object.entries(bundle)) {

342

if (chunk.type === 'chunk') {

343

// Generate safe namespace from file name

344

const safeName = makeLegalIdentifier(

345

fileName.replace(/\.[^.]+$/, '') // remove extension

346

);

347

348

// Wrap exports in namespace

349

const namespacedCode = `

350

(function(global) {

351

'use strict';

352

353

// Original code

354

${chunk.code}

355

356

// Create namespace

357

global.${namespace} = global.${namespace} || {};

358

global.${namespace}.${safeName} = exports;

359

360

})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this);

361

`;

362

363

chunk.code = namespacedCode;

364

}

365

}

366

}

367

};

368

}

369

```