Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
816d590
chore: vendor provider-feature availability matrix
so0k Jul 2, 2026
de9ad48
feat(lib): TerraformEphemeralResource with targetVersions validation
so0k Jul 2, 2026
402f21b
feat(provider-generator): acquire newer provider-protocol schema sect…
so0k Jul 2, 2026
4246f26
feat(provider-generator): generate ephemeral resource bindings
so0k Jul 2, 2026
fe3ecf2
feat(provider-generator): generate provider-defined function bindings
so0k Jul 2, 2026
014763e
feat(provider-generator): deprecate write-only attribute getters, val…
so0k Jul 2, 2026
d932180
feat(cli): thread targetVersions into cdktn get
so0k Jul 2, 2026
a382d96
fix(provider-generator): tolerate malformed targetVersions on the get…
so0k Jul 2, 2026
45d521a
fix(lib): restrict ephemeral resource lifecycle to pre/postconditions
so0k Jul 2, 2026
0b938e0
docs(provider-generator): warn against provider-fn self-reference in …
so0k Jul 2, 2026
268d54c
fix(lib): scope usage registries to one App synthesis session
so0k Jul 7, 2026
cd6d080
fix(provider-generator): warn about emission gaps on schema cache hit…
so0k Jul 7, 2026
b52a48b
docs: point the hand-maintained constraint maps at the vendored matrix
so0k Jul 7, 2026
f7c6c3b
fix(lib): render null provider-function arguments instead of dropping…
so0k Jul 7, 2026
68bdcdc
fix(provider-generator): return raw resolvable for dynamic provider-f…
so0k Jul 7, 2026
82e34b4
refactor(lib): type registerProviderFeatureUsage with a ProviderFeatu…
so0k Jul 13, 2026
30b1724
test: add version-boundary scenarios for target-version checks
so0k Jul 13, 2026
267360b
fix(provider-generator): model provider-function schema JSON accurately
so0k Jul 18, 2026
80945aa
feat(provider-generator): recursive, honest provider-function type ma…
so0k Jul 18, 2026
8a1af87
fix(lib): own function usage registries by App instead of process
so0k Jul 18, 2026
8bf9ddf
feat(provider-generator): move provider functions onto the provider c…
so0k Jul 18, 2026
99ab8e5
fix(lib): provider-feature hook on TerraformElement, honest enum inde…
so0k Jul 18, 2026
d6e859f
fix(provider-generator): make generated provider-function code run un…
so0k Jul 18, 2026
58cd428
test(provider-generator): edge-provider compile coverage for function…
so0k Jul 18, 2026
045ecb2
fix(provider-generator): reserve generated wrapper member names in fu…
so0k Jul 18, 2026
60d933c
fix(lib)!: write-only target validation derives from rendered values,…
so0k Jul 18, 2026
fc5cd9d
fix(lib): HCL renderer omits attribute descriptors whose value resolv…
so0k Jul 18, 2026
0eb1a1a
fix(lib): provider-feature and function usage represent the current s…
so0k Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/@cdktn/cli-core/src/lib/cdktf-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
Language,
Errors,
CONFIG_DEFAULTS,
validateTargetVersions,
type LanguageOptions,
type TerraformDependencyConstraint,
type TerraformTargetVersions,
} from "@cdktn/commons";
import path from "path";
import { logger } from "@cdktn/commons";
Expand Down Expand Up @@ -87,6 +89,24 @@ export class CdktfConfig {
return options;
}

public get targetVersions(): TerraformTargetVersions | undefined {
const targetVersions = this.getProperty("targetVersions") as
| TerraformTargetVersions
| undefined;

const problems = validateTargetVersions(targetVersions);
if (problems.length > 0) {
logger.warn(
`cdktf.json \`targetVersions\` is invalid and will be ignored:\n ${problems.join(
"\n ",
)}`,
);
return undefined;
}

return targetVersions;
}

public get terraformProviders(): (TerraformDependencyConstraint | string)[] {
const providers = this.getProperty("terraformProviders");
if (!Array.isArray(providers)) return [];
Expand Down
1 change: 1 addition & 0 deletions packages/@cdktn/cli-core/src/lib/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export async function runGetInDir(dir: string, clean = true) {
targetLanguage: config.language,
jsiiParallelism: 1,
languageOptions: config.languageOptions,
targetVersions: config.targetVersions,
},
cleanDirectory: clean,
});
Expand Down
55 changes: 55 additions & 0 deletions packages/@cdktn/cli-core/src/test/lib/cdktf-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) HashiCorp, Inc
// SPDX-License-Identifier: MPL-2.0
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { logger } from "@cdktn/commons";
import { CdktfConfig } from "../../lib/cdktf-config";

describe("CdktfConfig.targetVersions", () => {
let tmpDir: string;

beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "cdktf-config-test-"));
});

afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
jest.restoreAllMocks();
});

function writeConfig(targetVersions: unknown): string {
const cdktfConfigPath = path.join(tmpDir, "cdktf.json");
fs.writeFileSync(
cdktfConfigPath,
JSON.stringify({ language: "typescript", app: "", targetVersions }),
);
return cdktfConfigPath;
}

it("returns a well-formed targetVersions unchanged", () => {
const cdktfConfigPath = writeConfig({ terraform: ">=1.5.7" });
const config = new CdktfConfig(cdktfConfigPath);

expect(config.targetVersions).toEqual({ terraform: ">=1.5.7" });
});

it("warns and returns undefined for a malformed targetVersions instead of throwing", () => {
const warnSpy = jest.spyOn(logger, "warn").mockImplementation(() => {});
const cdktfConfigPath = writeConfig({ terraform: "not-a-range" });
const config = new CdktfConfig(cdktfConfigPath);

expect(() => config.targetVersions).not.toThrow();
expect(config.targetVersions).toBeUndefined();
expect(warnSpy).toHaveBeenCalledWith(
expect.stringContaining("not-a-range"),
);
});

it("returns undefined when targetVersions is not declared", () => {
const cdktfConfigPath = writeConfig(undefined);
const config = new CdktfConfig(cdktfConfigPath);

expect(config.targetVersions).toBeUndefined();
});
});
61 changes: 61 additions & 0 deletions packages/@cdktn/commons/src/provider-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,72 @@ export interface ProviderSchema {
format_version?: "0.1" | "0.2";
provider_schemas?: { [fqpn: string]: Provider };
provider_versions?: { [fqpn: string]: string };
/**
* Name of the CLI (terraform/opentofu) that fetched this schema, stamped
* by readProviderSchema. Used to reason about which newer-protocol
* sections (functions, ephemeral resources, ...) this particular fetch
* could possibly have emitted.
*/
cli_name?: string;
/**
* Version of the CLI that fetched this schema, e.g. "1.7.5".
*/
cli_version?: string;
}

export interface Provider {
provider: Schema;
resource_schemas: { [type: string]: Schema };
data_source_schemas: { [type: string]: Schema };
// list_resource_schemas, action_schemas and state_store_schemas are real
// sections of `terraform providers schema -json` (Terraform-only today;
// OpenTofu emits none). They are intentionally left untyped and
// unconsumed: they pass through parse/sanitize/cache verbatim so cached
// schemas stay complete, but no bindings are generated for them yet
// (deferred - RFC-04 Phase 4; re-evaluate when opentofu/opentofu#3787
// lands).
ephemeral_resource_schemas?: { [type: string]: Schema };
functions?: { [name: string]: FunctionSignature };
resource_identity_schemas?: { [type: string]: ResourceIdentitySchema };
}

/**
* A single parameter (or the variadic parameter) of a provider function.
* The providers-schema JSON fields are exactly: name, description,
* is_nullable, type. `is_nullable` derives from the plugin-protocol
* `AllowNullValue` field and means the parameter accepts an explicit null
* argument. Other protocol-only fields (e.g. `allow_unknown_values`) never
* reach the providers-schema JSON.
*/
export interface FunctionParameter {
name?: string;
type: AttributeType;
description?: string;
is_nullable?: boolean;
}

export interface FunctionSignature {
Comment thread
jsteinich marked this conversation as resolved.
description?: string;
summary?: string;
// Emitted by Terraform (>=1.8) for provider-defined functions; OpenTofu
// does not emit this field at all - a real divergence, do not "fix" by
// expecting parity.
deprecation_message?: string;
return_type: AttributeType;
parameters?: FunctionParameter[];
variadic_parameter?: FunctionParameter;
}

export interface IdentityAttribute {
type?: AttributeType;
description?: string;
required_for_import?: boolean;
optional_for_import?: boolean;
}

export interface ResourceIdentitySchema {
version: number;
attributes: { [name: string]: IdentityAttribute };
}

export interface Schema {
Expand Down Expand Up @@ -58,6 +118,7 @@ interface BaseAttribute {
optional?: boolean;
computed?: boolean;
sensitive?: boolean;
write_only?: boolean;
Comment thread
jsteinich marked this conversation as resolved.
}

interface NestedTypeAttribute extends BaseAttribute {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export * as listBlockResource from './list-block-resource/index';
export * as mapResource from './map-resource/index';
export * as setBlockResource from './set-block-resource/index';
export * as mapListResource from './map-list-resource/index';
export * as ephemeralCachedSecret from './ephemeral-cached-secret/index';
export * as provider from './provider/index';
export * as providerFunctions from './provider-functions/index';

"
`;
Expand All @@ -23,7 +25,9 @@ Object.defineProperty(exports, 'listBlockResource', { get: function () { return
Object.defineProperty(exports, 'mapResource', { get: function () { return require('./map-resource'); } });
Object.defineProperty(exports, 'setBlockResource', { get: function () { return require('./set-block-resource'); } });
Object.defineProperty(exports, 'mapListResource', { get: function () { return require('./map-list-resource'); } });
Object.defineProperty(exports, 'ephemeralCachedSecret', { get: function () { return require('./ephemeral-cached-secret'); } });
Object.defineProperty(exports, 'provider', { get: function () { return require('./provider'); } });
Object.defineProperty(exports, 'providerFunctions', { get: function () { return require('./provider-functions'); } });

"
`;
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
// Copyright (c) HashiCorp, Inc
// SPDX-License-Identifier: MPL-2.0
import { ProviderSchema, Schema, AttributeType, Block } from "@cdktn/commons";
import {
ProviderSchema,
Schema,
AttributeType,
Block,
FunctionSignature,
} from "@cdktn/commons";

type ResourceSchema = { [type: string]: Schema };
type FunctionSchema = { [name: string]: FunctionSignature };
export function schema({
name,
provider,
resources = {},
dataSources = {},
ephemeralResources = {},
functions = {},
}: {
name: string;
provider: Schema;
resources: ResourceSchema;
dataSources: ResourceSchema;
ephemeralResources?: ResourceSchema;
functions?: FunctionSchema;
}): ProviderSchema {
return {
format_version: "0.2",
Expand All @@ -21,6 +32,8 @@ export function schema({
provider: provider,
resource_schemas: resources,
data_source_schemas: dataSources,
ephemeral_resource_schemas: ephemeralResources,
functions: functions,
},
},
};
Expand All @@ -45,18 +58,21 @@ export class SchemaBuilder {
required = false,
computed = false,
optional = !required,
writeOnly = false,
}: {
name: string;
type: AttributeType;
required?: boolean;
computed?: boolean;
optional?: boolean;
writeOnly?: boolean;
}): SchemaBuilder {
this.schema.block.attributes[name] = {
type,
optional,
computed,
required,
write_only: writeOnly,
};
return this;
}
Expand Down
Loading
Loading