@intentius/chant-lexicon-azure 0.44.14 → 0.46.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.
Files changed (58) hide show
  1. package/dist/codegen/docs.d.ts.map +1 -1
  2. package/dist/deploy-scopes.d.ts.map +1 -1
  3. package/dist/describe-resources.d.ts.map +1 -1
  4. package/dist/generated/index.d.ts +328 -87
  5. package/dist/generated/index.d.ts.map +1 -1
  6. package/dist/integrity.json +4 -4
  7. package/dist/manifest.json +1 -1
  8. package/dist/meta.json +1923 -427
  9. package/dist/okf/index.md +22 -5
  10. package/dist/okf/rules/AZR028.md +1 -0
  11. package/dist/okf/types/{snapshots.md → Akssnapshots.md} +3 -3
  12. package/dist/okf/types/AzureStackHCIloadBalancers.md +21 -0
  13. package/dist/okf/types/AzureStackHCInatGateways.md +22 -0
  14. package/dist/okf/types/AzureStackHCInetworkSecurityGroups_securityRules.md +19 -0
  15. package/dist/okf/types/AzureStackHCIsnapshots.md +21 -0
  16. package/dist/okf/types/AzureStackHCIstorageContainers.md +21 -0
  17. package/dist/okf/types/AzureStackHCIvirtualMachineInstances.md +21 -0
  18. package/dist/okf/types/AzureStackHCIvirtualMachineInstances_guestAgents.md +18 -0
  19. package/dist/okf/types/AzureStackHCIvirtualNetworks.md +22 -0
  20. package/dist/okf/types/{storageContainers.md → DiscoverystorageContainers.md} +3 -3
  21. package/dist/okf/types/{loadBalancers.md → KubernetesRuntimeloadBalancers.md} +3 -3
  22. package/dist/okf/types/{natGateways.md → NetworknatGateways.md} +4 -4
  23. package/dist/okf/types/{networkSecurityGroups_securityRules.md → NetworknetworkSecurityGroups_securityRules.md} +3 -3
  24. package/dist/okf/types/galleryImages.md +21 -0
  25. package/dist/okf/types/logicalNetworks.md +21 -0
  26. package/dist/okf/types/marketplaceGalleryImages.md +21 -0
  27. package/dist/okf/types/natGateways_inboundRules.md +19 -0
  28. package/dist/okf/types/networkInterfaces.md +25 -0
  29. package/dist/okf/types/networkSecurityGroups.md +22 -0
  30. package/dist/okf/types/publicIPAddresses.md +21 -0
  31. package/dist/okf/types/virtualHardDisks.md +21 -0
  32. package/dist/okf/types/virtualNetworks_subnets.md +19 -0
  33. package/dist/op/activities/az-apply.d.ts +37 -23
  34. package/dist/op/activities/az-apply.d.ts.map +1 -1
  35. package/dist/op/activities/index.d.ts +1 -1
  36. package/dist/op/activities/index.d.ts.map +1 -1
  37. package/dist/serializer.d.ts +14 -0
  38. package/dist/serializer.d.ts.map +1 -1
  39. package/dist/spec/api-versions.d.ts +12 -0
  40. package/dist/spec/api-versions.d.ts.map +1 -1
  41. package/dist/types/index.d.ts +3682 -946
  42. package/dist/validate.d.ts.map +1 -1
  43. package/package.json +2 -2
  44. package/src/codegen/docs.ts +0 -16
  45. package/src/deploy-scopes.ts +19 -5
  46. package/src/describe-resources.ts +8 -0
  47. package/src/generated/index.d.ts +3682 -946
  48. package/src/generated/index.ts +328 -87
  49. package/src/generated/lexicon-azure.json +1923 -427
  50. package/src/lifecycle-integration.test.ts +40 -0
  51. package/src/op/activities/az-apply.test.ts +187 -21
  52. package/src/op/activities/az-apply.ts +104 -29
  53. package/src/op/activities/index.ts +1 -0
  54. package/src/serializer-api-versions.test.ts +94 -0
  55. package/src/serializer.ts +69 -32
  56. package/src/spec/api-versions.test.ts +16 -0
  57. package/src/spec/api-versions.ts +13 -0
  58. package/src/validate.ts +6 -0
package/src/serializer.ts CHANGED
@@ -18,6 +18,9 @@ import { AZURE_TAG_OWNERSHIP_KEYS } from "./ownership";
18
18
  import type { LexiconOutput } from "@intentius/chant/lexicon-output";
19
19
  import { walkValue, type SerializerVisitor } from "@intentius/chant/serializer-walker";
20
20
  import { isChildProject, type ChildProjectInstance } from "@intentius/chant/child-project";
21
+ import { existsSync, readFileSync } from "fs";
22
+ import { dirname, join } from "path";
23
+ import { fileURLToPath } from "url";
21
24
  import { isStackOutput, type StackOutput } from "@intentius/chant/stack-output";
22
25
  import { isAttrRefLike } from "@intentius/chant/utils";
23
26
  import { resolveDependsOn } from "@intentius/chant/resource-attributes";
@@ -74,42 +77,48 @@ const RESOURCE_LEVEL_FIELDS = new Set([
74
77
 
75
78
  /**
76
79
  * Load apiVersion for a resource type from the lexicon registry.
80
+ *
81
+ * Reads the generated registry (src/generated/lexicon-azure.json in a dev
82
+ * checkout, dist/meta.json in the installed package). Resolves the package
83
+ * directory from import.meta.url so it works under pure ESM as well as
84
+ * tsx/vitest — the old `require()`-based resolver threw under ESM and the
85
+ * throw was swallowed, so every resource emitted the fallback apiVersion
86
+ * (#1581). A missing registry is now an error: a uniform fallback apiVersion
87
+ * silently bypasses the per-provider pins in spec/api-versions.ts.
77
88
  */
78
89
  function resolveDir(): string {
79
- const { dirname } = require("path");
80
- // Bun / ESM
81
- try {
82
- const { fileURLToPath } = require("url");
83
- return dirname(fileURLToPath(import.meta.url));
84
- } catch {}
85
- // CJS / tsx fallback
86
- if (typeof __dirname !== "undefined") return __dirname;
87
- return dirname(require.resolve("./serializer"));
90
+ return dirname(fileURLToPath(import.meta.url));
91
+ }
92
+
93
+ export function apiVersionRegistryCandidates(dir: string = resolveDir()): string[] {
94
+ return [
95
+ join(dir, "generated", "lexicon-azure.json"),
96
+ join(dir, "..", "dist", "meta.json"),
97
+ ];
88
98
  }
89
99
 
90
- function loadApiVersions(): Map<string, string> {
100
+ export function loadApiVersions(candidates: string[] = apiVersionRegistryCandidates()): Map<string, string> {
91
101
  const map = new Map<string, string>();
92
- try {
93
- const { readFileSync } = require("fs");
94
- const { join } = require("path");
95
- const dir = resolveDir();
96
- // Try generated/ (dev) first, then dist/meta.json (installed package)
97
- let content: string | undefined;
98
- for (const candidate of [
99
- join(dir, "generated", "lexicon-azure.json"),
100
- join(dir, "..", "dist", "meta.json"),
101
- ]) {
102
- try { content = readFileSync(candidate, "utf-8"); break; } catch {}
103
- }
104
- if (!content) return map;
105
- const data = JSON.parse(content) as Record<string, { resourceType: string; apiVersion?: string }>;
106
- for (const entry of Object.values(data)) {
107
- if (entry.apiVersion && entry.resourceType) {
108
- map.set(entry.resourceType, entry.apiVersion);
109
- }
102
+ let content: string | undefined;
103
+ for (const candidate of candidates) {
104
+ if (!existsSync(candidate)) continue;
105
+ content = readFileSync(candidate, "utf-8");
106
+ break;
107
+ }
108
+ if (content === undefined) {
109
+ throw new Error(
110
+ `azure: apiVersion registry not found (tried ${candidates.join(", ")}). ` +
111
+ "Run `npm run generate` (dev) or reinstall the package (dist/meta.json).",
112
+ );
113
+ }
114
+ const data = JSON.parse(content) as Record<string, { resourceType: string; apiVersion?: string }>;
115
+ for (const entry of Object.values(data)) {
116
+ if (entry.apiVersion && entry.resourceType) {
117
+ map.set(entry.resourceType, entry.apiVersion);
110
118
  }
111
- } catch {
112
- // Lexicon not available
119
+ }
120
+ if (map.size === 0) {
121
+ throw new Error("azure: apiVersion registry is empty — regenerate with `npm run generate`");
113
122
  }
114
123
  return map;
115
124
  }
@@ -126,11 +135,39 @@ const API_VERSION_OVERRIDES = new Map<string, string>([
126
135
 
127
136
  let _apiVersions: Map<string, string> | undefined;
128
137
 
129
- function getApiVersion(resourceType: string): string {
138
+ /** Test hook: drop the cached registry so the next lookup reloads it. */
139
+ export function resetApiVersionCache(): void {
140
+ _apiVersions = undefined;
141
+ }
142
+
143
+ /**
144
+ * Registry lookup without the serializer's fallback: the pinned apiVersion for
145
+ * `resourceType`, or `undefined` when neither the overrides nor the generated
146
+ * registry know the type. ARM resource types are case-insensitive and the live
147
+ * listing does not always echo the casing the registry uses, so the match is
148
+ * case-insensitive too. Used by prune (#1472), which needs an apiVersion for a
149
+ * type the current template no longer declares.
150
+ */
151
+ export function lookupApiVersion(resourceType: string): string | undefined {
130
152
  const override = API_VERSION_OVERRIDES.get(resourceType);
131
153
  if (override) return override;
132
154
  if (!_apiVersions) _apiVersions = loadApiVersions();
133
- return _apiVersions.get(resourceType) ?? "2023-01-01";
155
+ const exact = _apiVersions.get(resourceType);
156
+ if (exact) return exact;
157
+ const wanted = resourceType.toLowerCase();
158
+ for (const [type, version] of _apiVersions) {
159
+ if (type.toLowerCase() === wanted) return version;
160
+ }
161
+ return undefined;
162
+ }
163
+
164
+ export function getApiVersion(resourceType: string): string {
165
+ const version = lookupApiVersion(resourceType);
166
+ if (version) return version;
167
+ console.warn(
168
+ `azure: no pinned apiVersion for ${resourceType} in the lexicon registry; falling back to 2023-01-01`,
169
+ );
170
+ return "2023-01-01";
134
171
  }
135
172
 
136
173
  /**
@@ -82,6 +82,22 @@ describe("PROVIDER_VERSION_OVERRIDES", () => {
82
82
  ]);
83
83
  });
84
84
 
85
+ it("keeps both pinned Microsoft.AzureStackHCI files, newest first (#1795)", () => {
86
+ // 2026-05-01-preview is the naive "latest by date" but carries only the
87
+ // cluster/edge family; the VM family lives in 2026-04-01-preview. The pin
88
+ // keeps both, in pin order, and drops the unpinned dates.
89
+ const paths = [
90
+ "schemas/2026-04-01-preview/Microsoft.AzureStackHCI.json",
91
+ "schemas/2026-04-30/Microsoft.AzureStackHCI.json",
92
+ "schemas/2026-05-01-preview/Microsoft.AzureStackHCI.json",
93
+ ];
94
+ const result = latestVersionPerProvider(paths);
95
+ expect(result.get("Microsoft.AzureStackHCI")?.map((f) => f.apiVersion)).toEqual([
96
+ "2026-05-01-preview",
97
+ "2026-04-01-preview",
98
+ ]);
99
+ });
100
+
85
101
  it("pins Microsoft.Management and Microsoft.Subscription to their latest GA dates (#1545)", () => {
86
102
  const paths = [
87
103
  "schemas/2023-04-01/Microsoft.Management.json",
@@ -76,6 +76,18 @@ export function parseSchemaPath(
76
76
  * no GA date and whose newer preview files (2024-12-01-preview and later)
77
77
  * drag in policy variables we don't want yet.
78
78
  *
79
+ * Microsoft.AzureStackHCI splits the same way (#1795): the newest dated file
80
+ * (2026-05-01-preview) carries only the cluster/edge-device family, while the
81
+ * VM family (virtualMachineInstances, virtualNetworks, networkInterfaces,
82
+ * publicIPAddresses, galleryImages, virtualHardDisks, ...) last appears in
83
+ * 2026-04-01-preview. Pin both, newest first — the cluster/edge family
84
+ * generates from 2026-05-01-preview and the VM family fills in from
85
+ * 2026-04-01-preview. `Microsoft.DataReplication/replicationVaults_
86
+ * privateEndpointConnectionProxies` dropped out in the same re-baseline but
87
+ * is NOT pinnable back: no dated Microsoft.DataReplication.json at the
88
+ * AZURE_SCHEMA_COMMIT pin (2021-02-16-preview, 2024-09-01, 2026-05-01)
89
+ * defines it — upstream removed the resource, so it stays gone.
90
+ *
79
91
  * Microsoft.Management and Microsoft.Subscription are pinned to their latest
80
92
  * GA dates: the naive latest for both is a preview (2024-02-01-preview adds
81
93
  * serviceGroups; 2025-11-01-preview adds changeTenantRequest), and the
@@ -83,6 +95,7 @@ export function parseSchemaPath(
83
95
  */
84
96
  export const PROVIDER_VERSION_OVERRIDES: Record<string, readonly string[]> = {
85
97
  "Microsoft.Authorization": ["2022-04-01", "2026-06-01", "2022-07-01-preview"],
98
+ "Microsoft.AzureStackHCI": ["2026-05-01-preview", "2026-04-01-preview"],
86
99
  "Microsoft.Compute": ["2026-03-01"],
87
100
  "Microsoft.Management": ["2023-04-01"],
88
101
  "Microsoft.Subscription": ["2021-10-01"],
package/src/validate.ts CHANGED
@@ -44,6 +44,12 @@ export async function validate(opts?: { basePath?: string }): Promise<ValidateRe
44
44
  // after bounding (#438), so match required names by substring.
45
45
  requiredNamesMatchSubstring: true,
46
46
  basePath,
47
+ // chant #1475 — azure generates from a commit sha of
48
+ // azure-resource-manager-schemas (#1144), so a fresh generate is
49
+ // deterministic. Gate the surface on every validate: the #1144 pin left
50
+ // the snapshot 483 entries behind until #1572 re-baselined it, because
51
+ // nothing compared the two on a PR.
52
+ checkSurfaceSnapshot: "always",
47
53
  coverageThresholds: {
48
54
  minPropertyPct: 1,
49
55
  minLifecyclePct: 1,