npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@hiscojs/jsonnet-updater

v1.4.0

Published

Type-safe, immutable Jsonnet updates with local variable management, function definitions, comment preservation, and advanced array merging strategies

Downloads

620

Readme

@hiscojs/jsonnet-updater

Type-safe, immutable Jsonnet updates with local variable management, function definitions, comment preservation, and advanced array merging strategies.

Features

  • 🔒 Type-safe updates using TypeScript proxies for automatic path detection
  • 🎯 Immutable operations - Original content never modified
  • 📝 Comment preservation - Keep your documentation intact
  • 📄 Document headers - Extract and preserve file headers with multiple formatting styles
  • 🔧 Local variables - Manage local declarations easily (similar to YAML anchors)
  • Function definitions - Create and manage reusable Jsonnet functions
  • 🔄 Advanced array merging - Multiple strategies (by name, by property, by content)
  • 📐 Formatting preservation - Maintains indentation and style
  • 🎨 Clean API - Intuitive, developer-friendly interface

Installation

npm install @hiscojs/jsonnet-updater

Quick Start

Basic Value Update

import { updateJsonnet } from '@hiscojs/jsonnet-updater';

const jsonnetString = `
{
  environment: 'dev',
  replicas: 3,
  image: 'myapp:1.0.0'
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj,
      merge: (orig) => ({
        ...orig,
        replicas: 5,
        image: 'myapp:2.0.0'
      })
    });
  }
});

console.log(result);
// Output:
// {
//   environment: 'dev',
//   replicas: 5,
//   image: 'myapp:2.0.0'
// }

Core Concepts

The annotate Pattern

The library uses a change function within annotate to specify updates. This provides type-safety and immutable updates:

annotate: ({ change }) => {
  change({
    findKey: (obj) => obj.parentObject,       // Find the parent object to update
    merge: (original) => ({                    // Return updated parent object
      ...original,                             // Spread original properties
      propertyToUpdate: newValue               // Override specific properties
    })
  });
}

Important: Always find the parent object containing the property you want to update, then return the complete updated parent object using the spread operator.

Return Type

All operations return a JsonnetEdit<T> object:

interface JsonnetEdit<T> {
  result: string;           // Updated Jsonnet string
  resultParsed: T;          // Parsed object (evaluated Jsonnet)
  originalParsed: T;        // Original parsed object
  locals: LocalVariable[];  // Defined local variables
  functions: LocalFunction[]; // Defined local functions
}

Working with Local Variables

Local variables in Jsonnet are like YAML anchors - they allow you to define reusable values.

Adding Local Variables

import { updateJsonnet } from '@hiscojs/jsonnet-updater';

const jsonnetString = `
{
  name: 'myapp',
  version: '1.0.0'
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  locals: [
    {
      name: 'namespace',
      value: 'production'
    },
    {
      name: 'imageTag',
      value: 'v2.0.0'
    }
  ],
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.namespace,
      merge: () => '$.namespace'  // Reference the local variable
    });
  }
});

console.log(result);
// Output:
// local namespace = 'production';
// local imageTag = 'v2.0.0';
// {
//   name: 'myapp',
//   version: '1.0.0',
//   namespace: $.namespace
// }

Using Existing Local Variables

const jsonnetString = `
local environment = 'dev';
local replicas = 3;

{
  env: environment,
  count: replicas
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  locals: [
    { name: 'replicas', value: 5 }  // Override the local variable
  ]
});

console.log(result);
// Output:
// local environment = 'dev';
// local replicas = 5;  // <-- Updated
//
// {
//   env: environment,
//   count: replicas
// }

Working with Local Functions

Local functions provide reusable logic, similar to how you might use YAML anchors for complex structures.

Defining Local Functions

import { updateJsonnet } from '@hiscojs/jsonnet-updater';

const jsonnetString = `
{
  services: []
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  functions: [
    {
      name: 'createService',
      params: ['name', 'port'],
      body: `{
  name: name,
  port: port,
  protocol: 'TCP'
}`
    }
  ],
  annotate: ({ change, functions }) => {
    change({
      findKey: (obj) => obj.services,
      merge: () => [
        '$.createService("api", 8080)',
        '$.createService("web", 3000)'
      ]
    });
  }
});

console.log(result);
// Output:
// local createService(name, port) = {
//   name: name,
//   port: port,
//   protocol: 'TCP'
// };
//
// {
//   services: [
//     $.createService("api", 8080),
//     $.createService("web", 3000)
//   ]
// }

Complex Function Example

const { result } = updateJsonnet({
  jsonnetString: '{}',
  functions: [
    {
      name: 'createDeployment',
      params: ['name', 'image', 'replicas'],
      body: `{
  apiVersion: 'apps/v1',
  kind: 'Deployment',
  metadata: {
    name: name
  },
  spec: {
    replicas: replicas,
    template: {
      spec: {
        containers: [{
          name: name,
          image: image
        }]
      }
    }
  }
}`
    }
  ],
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.deployment,
      merge: () => '$.createDeployment("myapp", "myapp:2.0", 3)'
    });
  }
});

Advanced Array Merging

Use addInstructions for sophisticated array handling:

import { updateJsonnet, addInstructions } from '@hiscojs/jsonnet-updater';

const jsonnetString = `
{
  services: [
    { name: 'api', port: 8080 },
    { name: 'web', port: 3000 }
  ]
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.services,
      merge: (current) => [
        ...current,
        ...addInstructions({
          prop: 'services',
          mergeByName: true  // Merge by 'name' property
        }),
        { name: 'api', port: 8081, replicas: 3 },  // Updates existing
        { name: 'cache', port: 6379 }              // Adds new
      ]
    });
  }
});

console.log(result);
// Output:
// {
//   services: [
//     { name: 'api', port: 8081, replicas: 3 },  // Merged by name
//     { name: 'web', port: 3000 },
//     { name: 'cache', port: 6379 }              // Added
//   ]
// }

Merge Strategies

...addInstructions({
  prop: 'arrayName',
  mergeByName: true,        // Merge by 'name' property
  // OR
  mergeByProp: 'id',        // Merge by specific property
  // OR
  mergeByContents: true,    // Merge by full content comparison

  deepMerge: true           // Deep merge objects (default: false)
})

Property Deletion

Delete properties using the exclude helper function:

import { updateJsonnet, exclude } from '@hiscojs/jsonnet-updater';

const jsonnetString = `
{
  name: 'myapp',
  version: '1.0.0',
  deprecated: true,
  legacy: 'old-value'
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj,
      merge: (orig) => exclude(orig, 'deprecated', 'legacy')
    });
  }
});

console.log(result);
// Output:
// {
//   name: 'myapp',
//   version: '1.0.0'
// }

Deleting Properties with Updates

Combine exclude with the spread operator for partial updates:

const { result } = updateJsonnet({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj,
      merge: (orig) => ({
        ...exclude(orig, 'deprecated'),
        version: '2.0.0',           // Update existing
        environment: 'production'    // Add new
      })
    });
  }
});

Deleting Nested Properties

const { result } = updateJsonnet({
  jsonnetString: `{
  server: {
    host: 'localhost',
    port: 8080,
    oldTimeout: 30
  }
}`,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.server,
      merge: (orig) => ({
        ...exclude(orig, 'oldTimeout'),
        timeout: 60  // Replace with new property
      })
    });
  }
});

Note: For deleting array elements, use standard JavaScript array methods like filter():

change({
  findKey: (obj) => obj.items,
  merge: (orig) => orig.filter(item => item.active)
});

Nested Object Updates

const jsonnetString = `
{
  server: {
    host: 'localhost',
    port: 8080,
    ssl: {
      enabled: false
    }
  }
}
`;

const { result } = updateJsonnet({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.server.ssl,
      merge: (orig) => ({
        ...orig,
        enabled: true,
        cert: '/path/to/cert.pem'
      })
    });
  }
});

console.log(result);
// Output:
// {
//   server: {
//     host: 'localhost',
//     port: 8080,
//     ssl: {
//       enabled: true,
//       cert: '/path/to/cert.pem'
//     }
//   }
// }

Document Headers

Preserve and manage document headers (comments at the top of the file):

Simple Headers

const jsonnetString = `# Application Configuration
# Version: 1.0
# Author: DevOps Team
{
  name: 'myapp',
  version: '1.0.0'
}`;

const { result, extractedHeader } = updateJsonnet({
  jsonnetString,
  documentHeader: {
    type: 'simple',
    content: ['Application Configuration', 'Version: 1.0', 'Author: DevOps Team']
  },
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj,
      merge: (orig) => ({
        ...orig,
        version: '2.0.0'
      })
    });
  }
});

// Output:
// # Application Configuration
// # Version: 1.0
// # Author: DevOps Team
// {
//   name: 'myapp',
//   version: '2.0.0'
// }

Multi-line Bordered Headers

const { result } = updateJsonnet({
  jsonnetString: '{ service: "api" }',
  documentHeader: {
    type: 'multi-line',
    content: ['Service Configuration', 'Owner: Platform Team'],
    border: '#',
    width: 50
  }
});

// Output:
// ##################################################
// # Service Configuration
// # Owner: Platform Team
// ##################################################
// {
//   service: 'api'
// }

Raw Headers

const { result } = updateJsonnet({
  jsonnetString: '{ generated: true }',
  documentHeader: {
    type: 'raw',
    content: '// Custom header format\n// DO NOT EDIT - Generated file'
  }
});

// Output:
// // Custom header format
// // DO NOT EDIT - Generated file
// {
//   generated: true
// }

Header Extraction

When a documentHeader is provided, the library automatically extracts existing headers:

const { extractedHeader } = updateJsonnet({
  jsonnetString: withHeader,
  documentHeader: { type: 'simple', content: [] }
});

console.log(extractedHeader);
// {
//   type: 'simple',
//   content: ['Application Configuration', 'Version: 1.0'],
//   raw: '# Application Configuration\n# Version: 1.0'
// }

Format Options

Control how the output is formatted:

const { result } = updateJsonnet({
  jsonnetString,
  formatOptions: {
    indent: 2,                    // Number of spaces (or '\t')
    preserveIndentation: true,    // Auto-detect from source (default)
    trailingNewline: true         // Add newline at end (default)
  },
  annotate: ({ change }) => {
    // Your updates...
  }
});

Real-World Examples

Kubernetes Manifest Generation

import { updateJsonnet } from '@hiscojs/jsonnet-updater';

const kubernetesTemplate = `
{
  apiVersion: 'v1',
  kind: 'ConfigMap',
  metadata: {
    name: 'app-config'
  },
  data: {}
}
`;

const { result } = updateJsonnet({
  jsonnetString: kubernetesTemplate,
  locals: [
    { name: 'environment', value: 'production' },
    { name: 'region', value: 'us-west-2' }
  ],
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.metadata,
      merge: (orig) => ({
        ...orig,
        namespace: '$.environment'
      })
    });

    change({
      findKey: (obj) => obj,
      merge: (orig) => ({
        ...orig,
        data: {
          DATABASE_URL: 'postgres://prod-db:5432',
          REGION: '$.region',
          LOG_LEVEL: 'info'
        }
      })
    });
  }
});

Multi-Service Configuration

const { result } = updateJsonnet({
  jsonnetString: '{}',
  functions: [
    {
      name: 'createService',
      params: ['name', 'image', 'port', 'env'],
      body: `{
  name: name,
  image: image,
  ports: [{ containerPort: port }],
  env: env
}`
    }
  ],
  locals: [
    { name: 'dbHost', value: 'postgres.example.com' },
    { name: 'cacheHost', value: 'redis.example.com' }
  ],
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.services,
      merge: () => [
        `$.createService(
          "api",
          "api:2.0",
          8080,
          [{ name: "DB_HOST", value: $.dbHost }]
        )`,
        `$.createService(
          "worker",
          "worker:1.5",
          8081,
          [
            { name: "DB_HOST", value: $.dbHost },
            { name: "CACHE_HOST", value: $.cacheHost }
          ]
        )`
      ]
    });
  }
});

API Reference

updateJsonnet<T>(options): JsonnetEdit<T>

Main function for updating Jsonnet content.

Options:

{
  jsonnetString: string;              // Input Jsonnet content
  annotate?: (ctx: AnnotateContext) => void;  // Update callback
  formatOptions?: FormatOptions;      // Formatting preferences
  locals?: LocalVariable[];           // Local variable definitions
  functions?: LocalFunction[];        // Local function definitions
  documentHeader?: DocumentHeader;    // Document header configuration
}

Return Type:

interface JsonnetEdit<T> {
  result: string;                     // Updated Jsonnet string
  resultParsed: T;                    // Parsed updated object
  originalParsed: T;                  // Original parsed object
  locals: LocalVariable[];            // Defined local variables
  functions: LocalFunction[];         // Defined local functions
  extractedHeader?: ExtractedHeader;  // Extracted document header (if present)
}

AnnotateContext:

{
  change: (instruction: ChangeInstruction) => void;
  locals: Record<string, any>;        // Access to local variables
  functions: Record<string, Function>; // Access to local functions
}

ChangeInstruction:

{
  findKey: (proxy: T) => any;         // Path selector with type-safety
  merge: (current: any) => any;       // Update function
}

DocumentHeader:

{
  type: 'simple' | 'multi-line' | 'raw';  // Header formatting style
  content: string | string[];              // Header content
  border?: string;                         // Border char for multi-line (default: '#')
  width?: number;                          // Width for multi-line (default: auto)
}

ExtractedHeader:

{
  type: 'simple' | 'multi-line' | 'raw';  // Detected header type
  content: string[];                       // Parsed content lines
  raw: string;                             // Raw header string
}

addInstructions(options): Instruction[]

Generate instructions for advanced array merging (re-exported from @hiscojs/object-updater).

Options:

{
  prop: string;              // Array property name
  mergeByName?: boolean;     // Merge by 'name' property
  mergeByProp?: string;      // Merge by specific property
  mergeByContents?: boolean; // Merge by content comparison
  deepMerge?: boolean;       // Deep merge objects
}

exclude<T>(obj: T, ...keys: (keyof T)[]): Partial<T>

Helper function for deleting properties from objects (re-exported from @hiscojs/object-updater).

Parameters:

  • obj: The source object
  • keys: Property names to exclude/delete (variable number of arguments)

Returns: A new object with specified properties set to undefined, signaling deletion

Example:

import { updateJsonnet, exclude } from '@hiscojs/jsonnet-updater';

// Delete single property
merge: (orig) => exclude(orig, 'deprecated')

// Delete multiple properties
merge: (orig) => exclude(orig, 'deprecated', 'legacy', 'old')

// Combine with spread for updates
merge: (orig) => ({
  ...exclude(orig, 'deprecated'),
  version: '2.0.0',
  newProp: 'value'
})

TypeScript Support

Full TypeScript support with generic types:

interface MyConfig {
  server: {
    host: string;
    port: number;
  };
  features: string[];
}

const { result, resultParsed } = updateJsonnet<MyConfig>({
  jsonnetString,
  annotate: ({ change }) => {
    change({
      findKey: (obj) => obj.server.port,  // Type-safe!
      merge: () => 9000
    });
  }
});

// resultParsed is typed as MyConfig
console.log(resultParsed.server.host);

Known Limitations

While jsonnet-updater is powerful for many use cases, it has some limitations:

Parsing Limitations

  • Cannot parse Jsonnet files with function calls in data values (e.g., person1: Person())
  • Complex Jsonnet expressions may not parse correctly
  • Best used with static JSON-like Jsonnet structures

Function Evaluation

  • Functions are not evaluated (treated as templates)
  • Function calls are represented as string references ($.functionName())

Comment Preservation

  • Comments are tracked but not fully re-inserted
  • Basic comment preservation implementation

Recommended Use Cases

✅ Best For

  • Creating Jsonnet files from scratch with functions and local variables
  • Updating static JSON-like Jsonnet structures with predictable schemas
  • Managing local variables and functions as reusable templates
  • Kubernetes manifest generation with templating
  • Configuration file templating for multi-environment setups

⚠️ Not Ideal For

  • Complex Jsonnet with heavy use of function calls in data
  • Files with computed values and conditionals that require evaluation
  • Interactive Jsonnet evaluation or runtime value computation

Comparison with Other Updaters

| Feature | jsonnet-updater | yaml-updater | json-updater | |---------|----------------|--------------|--------------| | Type-safe updates | ✅ | ✅ | ✅ | | Comment preservation | ✅ | ✅ | ✅ | | Local variables | ✅ (native) | ✅ (anchors) | ❌ | | Functions | ✅ (native) | ❌ | ❌ | | Array merging | ✅ | ✅ | ✅ | | Multi-document | ❌ | ✅ | ❌ | | Format detection | ✅ | ✅ | ✅ |

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Programmatic Generation

For cases where you need to generate Jsonnet from scratch rather than update existing files, the library provides two approaches:

1. JavaScript-Native API (Recommended ⭐)

Write plain JavaScript objects and use helpers only when needed - similar to yaml-updater's addInstructions.

import {
  objectToJsonnet,
  identifier,
  extVar,
  concat,
  addInstructions,
} from '@hiscojs/jsonnet-updater';

const template = objectToJsonnet(
  {
    apiVersion: 'argoproj.io/v1alpha1',
    kind: 'AppProject',
    metadata: {
      name: identifier('projectName'), // Variable reference
      namespace: 'argocd',
    },
    spec: {
      description: concat('Project: ', identifier('projectName')), // String concatenation
      sourceRepos: ['*'],

      // Explicit array formatting control (like yaml-updater)
      ...addInstructions({ prop: 'destinations', multiline: true }),
      destinations: [
        {
          server: identifier('clusterAddress'),
          namespace: '*',
        },
      ],
    },
  },
  {
    locals: [
      { name: 'projectName', value: extVar('projectName') },
      { name: 'clusterAddress', value: extVar('clusterAddress') },
    ],
  }
);

// Output:
// {
//   local projectName = std.extVar("projectName");
//   local clusterAddress = std.extVar("clusterAddress");
//
//   apiVersion: "argoproj.io/v1alpha1",
//   kind: "AppProject",
//   metadata: {
//     name: projectName,
//     namespace: "argocd",
//   },
//   spec: {
//     description: "Project: " + projectName,
//     sourceRepos: ["*"],
//     destinations: [
//       {
//         server: clusterAddress,
//         namespace: "*",
//       },
//     ],
//   },
// }

Helpers:

  • identifier(name) - Variable reference: identifier('var')var
  • extVar(name) - External variable: extVar('name')std.extVar("name")
  • concat(left, right) - String concatenation: concat('a', 'b')"a" + "b"
  • addInstructions({ prop, multiline }) - Array formatting control (like yaml-updater)

See OBJECT_API.md for complete documentation.

2. AST Builders (Low-Level)

For cases where you need to generate Jsonnet from scratch rather than update existing files, the library provides AST builder helpers.

Quick Example

import { generate, Document } from '@hiscojs/jsonnet-updater';
import * as b from '@hiscojs/jsonnet-updater/builders';

// Build the AST
const ast: Document = {
  type: 'Document',
  body: b.object(
    [
      b.field('apiVersion', b.string('v1')),
      b.field('kind', b.string('ConfigMap')),
      b.field('metadata', b.object([
        b.field('name', b.identifier('appName')),
        b.field('namespace', b.string('default')),
      ])),
      b.field('data', b.object([
        b.field('config.json', b.string('{"key": "value"}')),
      ])),
    ],
    // Local variables (second parameter)
    [
      b.local('appName', b.extVar('appName')),
    ]
  ),
};

// Generate Jsonnet code
const result = generate(ast, {
  indent: '  ',
  trailingCommas: true,
});

console.log(result);
// Output:
// {
//   local appName = std.extVar("appName");
//
//   apiVersion: "v1",
//   kind: "ConfigMap",
//   metadata: {
//     name: appName,
//     namespace: "default",
//   },
//   data: {
//     "config.json": "{\"key\": \"value\"}",
//   },
// }

Builder API

| Builder | Output | Description | |---------|--------|-------------| | b.string('text') | "text" | String literal | | b.number(42) | 42 | Number literal | | b.boolean(true) | true | Boolean literal | | b.identifier('name') | name | Variable reference | | b.extVar('var') | std.extVar("var") | External variable | | b.object([...]) | { ... } | Object | | b.array([...]) | [...] | Array | | b.field('key', value) | key: value | Object field | | b.local('name', value) | local name = value | Local variable | | b.binary('+', a, b) | a + b | Binary expression | | b.call(func, [args]) | func(args) | Function call | | b.member(obj, 'prop') | obj.prop | Member access |

Array Formatting Control

Control whether arrays are formatted inline or multi-line:

// Auto-detect (default): inline for simple values, multi-line for objects
b.array([b.string('a'), b.string('b')])  // ["a", "b"]
b.array([b.object([...])])                // [{\n  ...\n}]

// Force multi-line (explicit control)
b.array(
  [b.string('dev'), b.string('staging'), b.string('prod')],
  { multiline: true }
)
// Output:
// [
//   "dev",
//   "staging",
//   "prod",
// ]

// Force inline
b.array([...], { multiline: false })  // [...]

Array Formatting Options:

  • multiline: true - Force multi-line format
  • multiline: false - Force inline format
  • undefined - Auto-detect based on element types (default)

Complete Example: ArgoCD AppProject

See appproject-template.jsonnet for a complete example of generating a complex Jsonnet template programmatically.

import { generate, Document } from '@hiscojs/jsonnet-updater';
import * as b from '@hiscojs/jsonnet-updater/builders';

const ast: Document = {
  type: 'Document',
  body: b.object(
    [
      b.field('apiVersion', b.string('argoproj.io/v1alpha1')),
      b.field('kind', b.string('AppProject')),
      b.field('metadata', b.object([
        b.field('name', b.identifier('projectName')),
        b.field('namespace', b.string('argocd')),
      ])),
      b.field('spec', b.object([
        b.field(
          'description',
          b.binary('+', b.string('Project: '), b.identifier('projectName'))
        ),
        b.field('sourceRepos', b.array([b.string('*')])),
        b.field(
          'destinations',
          b.array(
            [
              b.object([
                b.field('server', b.identifier('clusterAddress')),
                b.field('namespace', b.string('*')),
              ]),
            ],
            { multiline: true }  // Explicit multi-line formatting
          )
        ),
      ])),
    ],
    [
      b.local('projectName', b.extVar('projectName')),
      b.local('clusterAddress', b.extVar('clusterAddress')),
    ]
  ),
};

const result = generate(ast, { indent: '  ', trailingCommas: true });

When to Use Programmatic Generation

✅ Use AST builders when:

  • Creating Jsonnet files from scratch
  • Building templates dynamically from data
  • Need type-safe construction with validation
  • Generating consistent structures programmatically

✅ Use updateJsonnet() when:

  • Updating existing Jsonnet files
  • Preserving comments and formatting
  • Making incremental changes to existing content

Related Libraries