@intentius/chant-lexicon-azure 0.124.31 → 0.124.33

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 (144) hide show
  1. package/dist/actions/appservice.js +7 -0
  2. package/dist/actions/compute.js +9 -0
  3. package/dist/actions/container.js +14 -0
  4. package/dist/actions/identity.js +11 -0
  5. package/dist/actions/index.js +11 -0
  6. package/dist/actions/keyvault.js +12 -0
  7. package/dist/actions/network.js +9 -0
  8. package/dist/actions/sql.js +9 -0
  9. package/dist/actions/storage.js +15 -0
  10. package/dist/api/read-client.js +146 -0
  11. package/dist/codegen/docs-cli.js +2 -0
  12. package/dist/codegen/docs.js +83 -0
  13. package/dist/codegen/generate-cli.js +11 -0
  14. package/dist/codegen/generate-lexicon.js +77 -0
  15. package/dist/codegen/generate-typescript.js +163 -0
  16. package/dist/codegen/generate.js +106 -0
  17. package/dist/codegen/naming.js +139 -0
  18. package/dist/codegen/package.js +64 -0
  19. package/dist/composites/aks-cluster.js +68 -0
  20. package/dist/composites/app-service.js +62 -0
  21. package/dist/composites/application-gateway.js +107 -0
  22. package/dist/composites/catalog.js +856 -0
  23. package/dist/composites/container-instance.js +36 -0
  24. package/dist/composites/container-registry.js +62 -0
  25. package/dist/composites/cosmos-database.js +56 -0
  26. package/dist/composites/from-arm.js +47 -0
  27. package/dist/composites/function-app.js +57 -0
  28. package/dist/composites/index.js +16 -0
  29. package/dist/composites/keyvault.js +69 -0
  30. package/dist/composites/landing-zone.js +119 -0
  31. package/dist/composites/private-endpoint.js +61 -0
  32. package/dist/composites/redis-cache.js +21 -0
  33. package/dist/composites/service-bus-pipeline.js +54 -0
  34. package/dist/composites/sql-database.js +62 -0
  35. package/dist/composites/storage-account.js +59 -0
  36. package/dist/composites/vm-linux.js +139 -0
  37. package/dist/composites/vnet-default.js +102 -0
  38. package/dist/coverage.js +28 -0
  39. package/dist/deep-observe.js +356 -0
  40. package/dist/default-tags.js +50 -0
  41. package/dist/deploy-scopes.d.ts.map +1 -1
  42. package/dist/deploy-scopes.js +157 -0
  43. package/dist/describe-resources.js +187 -0
  44. package/dist/detect.js +17 -0
  45. package/dist/export-resources.js +108 -0
  46. package/dist/generated/index.d.ts.map +1 -1
  47. package/dist/generated/index.js +16598 -0
  48. package/dist/generated/runtime.js +4 -0
  49. package/dist/governance.js +144 -0
  50. package/dist/health.d.ts +42 -0
  51. package/dist/health.d.ts.map +1 -0
  52. package/dist/health.js +137 -0
  53. package/dist/import/generator.js +140 -0
  54. package/dist/import/live-export.js +39 -0
  55. package/dist/import/parser.js +192 -0
  56. package/dist/index.js +44 -0
  57. package/dist/integrity.json +5 -5
  58. package/dist/intrinsics.js +179 -0
  59. package/dist/lint/audit-catalog.js +36 -0
  60. package/dist/lint/audit-lineage.js +71 -0
  61. package/dist/lint/post-synth/arm-refs.d.ts +1 -0
  62. package/dist/lint/post-synth/arm-refs.d.ts.map +1 -1
  63. package/dist/lint/post-synth/arm-refs.js +96 -0
  64. package/dist/lint/post-synth/azr010.js +45 -0
  65. package/dist/lint/post-synth/azr011.js +43 -0
  66. package/dist/lint/post-synth/azr012.js +41 -0
  67. package/dist/lint/post-synth/azr013.js +50 -0
  68. package/dist/lint/post-synth/azr014.js +49 -0
  69. package/dist/lint/post-synth/azr015.js +66 -0
  70. package/dist/lint/post-synth/azr016.js +37 -0
  71. package/dist/lint/post-synth/azr017.js +37 -0
  72. package/dist/lint/post-synth/azr018.js +42 -0
  73. package/dist/lint/post-synth/azr019.js +41 -0
  74. package/dist/lint/post-synth/azr020.js +37 -0
  75. package/dist/lint/post-synth/azr021.js +36 -0
  76. package/dist/lint/post-synth/azr022.js +39 -0
  77. package/dist/lint/post-synth/azr023.js +39 -0
  78. package/dist/lint/post-synth/azr024.js +39 -0
  79. package/dist/lint/post-synth/azr025.js +37 -0
  80. package/dist/lint/post-synth/azr026.js +38 -0
  81. package/dist/lint/post-synth/azr027.js +37 -0
  82. package/dist/lint/post-synth/azr028.js +37 -0
  83. package/dist/lint/post-synth/azr029.js +38 -0
  84. package/dist/lint/post-synth/azr030.js +44 -0
  85. package/dist/lint/post-synth/azr031.js +36 -0
  86. package/dist/lint/post-synth/azr032.js +53 -0
  87. package/dist/lint/post-synth/azr033.js +35 -0
  88. package/dist/lint/post-synth/index.js +50 -0
  89. package/dist/lint/rules/hardcoded-location.js +82 -0
  90. package/dist/lint/rules/index.js +6 -0
  91. package/dist/lint/rules/nsg-wildcard.js +44 -0
  92. package/dist/lint/rules/storage-https.js +62 -0
  93. package/dist/lsp/completions.d.ts.map +1 -1
  94. package/dist/lsp/completions.js +18 -0
  95. package/dist/lsp/hover.d.ts.map +1 -1
  96. package/dist/lsp/hover.js +44 -0
  97. package/dist/manifest.json +1 -1
  98. package/dist/meta.json +6 -1
  99. package/dist/okf/types/containerApps.md +5 -0
  100. package/dist/op/activities/az-apply.js +563 -0
  101. package/dist/op/activities/azure.js +48 -0
  102. package/dist/op/activities/floci-az.js +37 -0
  103. package/dist/op/activities/index.js +10 -0
  104. package/dist/op/builders.js +70 -0
  105. package/dist/ownership.js +13 -0
  106. package/dist/package-cli.js +21 -0
  107. package/dist/parameter.js +13 -0
  108. package/dist/plugin.d.ts.map +1 -1
  109. package/dist/plugin.js +478 -0
  110. package/dist/pseudo.js +40 -0
  111. package/dist/rules/arm-refs.ts +5 -3
  112. package/dist/serializer.d.ts +7 -0
  113. package/dist/serializer.d.ts.map +1 -1
  114. package/dist/serializer.js +543 -0
  115. package/dist/spec/api-versions.js +130 -0
  116. package/dist/spec/fetch.js +196 -0
  117. package/dist/spec/parse.d.ts.map +1 -1
  118. package/dist/spec/parse.js +318 -0
  119. package/dist/taggable.js +34 -0
  120. package/dist/types/index.d.ts +5 -0
  121. package/dist/validate-cli.js +16 -0
  122. package/dist/validate.js +53 -0
  123. package/package.json +8 -8
  124. package/src/attributes.test.ts +17 -0
  125. package/src/codegen/generate-typescript.ts +1 -1
  126. package/src/codegen/generate.ts +1 -1
  127. package/src/codegen/package.ts +2 -2
  128. package/src/deploy-scopes.ts +2 -1
  129. package/src/generated/index.d.ts +5 -0
  130. package/src/generated/index.ts +1 -1
  131. package/src/generated/lexicon-azure.json +6 -1
  132. package/src/health.test.ts +66 -0
  133. package/src/health.ts +162 -0
  134. package/src/lint/post-synth/arm-refs.ts +5 -3
  135. package/src/lint/post-synth/post-synth.test.ts +1 -1
  136. package/src/lsp/completions.ts +2 -1
  137. package/src/lsp/hover.ts +2 -1
  138. package/src/plugin.ts +11 -2
  139. package/src/serializer-names.test.ts +83 -0
  140. package/src/serializer-outputs.test.ts +65 -0
  141. package/src/serializer.ts +112 -30
  142. package/src/spec/parse.test.ts +15 -0
  143. package/src/spec/parse.ts +10 -0
  144. package/src/taggable.ts +2 -2
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Azure App Service RBAC built-in role constants.
3
+ */
4
+ export const AppServiceRoles = {
5
+ WebPlanContributor: "Web Plan Contributor",
6
+ WebsiteContributor: "Website Contributor",
7
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Azure Compute RBAC built-in role constants.
3
+ */
4
+ export const ComputeRoles = {
5
+ VirtualMachineContributor: "Virtual Machine Contributor",
6
+ VirtualMachineAdminLogin: "Virtual Machine Administrator Login",
7
+ VirtualMachineUserLogin: "Virtual Machine User Login",
8
+ DiskSnapshotContributor: "Disk Snapshot Contributor",
9
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Azure Container RBAC built-in role constants (AKS + ACR).
3
+ */
4
+ export const ContainerRoles = {
5
+ AksClusterAdmin: "Azure Kubernetes Service Cluster Admin Role",
6
+ AksClusterUser: "Azure Kubernetes Service Cluster User Role",
7
+ AksContributor: "Azure Kubernetes Service Contributor Role",
8
+ AksRbacAdmin: "Azure Kubernetes Service RBAC Admin",
9
+ AksRbacReader: "Azure Kubernetes Service RBAC Reader",
10
+ AcrPull: "AcrPull",
11
+ AcrPush: "AcrPush",
12
+ AcrDelete: "AcrDelete",
13
+ AcrImageSigner: "AcrImageSigner",
14
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Azure Identity & Access RBAC built-in role constants.
3
+ */
4
+ export const IdentityRoles = {
5
+ Contributor: "Contributor",
6
+ Owner: "Owner",
7
+ Reader: "Reader",
8
+ UserAccessAdministrator: "User Access Administrator",
9
+ ManagedIdentityContributor: "Managed Identity Contributor",
10
+ ManagedIdentityOperator: "Managed Identity Operator",
11
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Azure RBAC built-in role constants — barrel export.
3
+ */
4
+ export { StorageRoles } from "./storage.js";
5
+ export { ComputeRoles } from "./compute.js";
6
+ export { NetworkRoles } from "./network.js";
7
+ export { KeyVaultRoles } from "./keyvault.js";
8
+ export { SqlRoles } from "./sql.js";
9
+ export { ContainerRoles } from "./container.js";
10
+ export { AppServiceRoles } from "./appservice.js";
11
+ export { IdentityRoles } from "./identity.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Azure Key Vault RBAC built-in role constants.
3
+ */
4
+ export const KeyVaultRoles = {
5
+ Administrator: "Key Vault Administrator",
6
+ CertificatesOfficer: "Key Vault Certificates Officer",
7
+ CryptoOfficer: "Key Vault Crypto Officer",
8
+ CryptoUser: "Key Vault Crypto User",
9
+ Reader: "Key Vault Reader",
10
+ SecretsOfficer: "Key Vault Secrets Officer",
11
+ SecretsUser: "Key Vault Secrets User",
12
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Azure Network RBAC built-in role constants.
3
+ */
4
+ export const NetworkRoles = {
5
+ NetworkContributor: "Network Contributor",
6
+ DnsZoneContributor: "DNS Zone Contributor",
7
+ PrivateDnsZoneContributor: "Private DNS Zone Contributor",
8
+ TrafficManagerContributor: "Traffic Manager Contributor",
9
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Azure SQL RBAC built-in role constants.
3
+ */
4
+ export const SqlRoles = {
5
+ ServerContributor: "SQL Server Contributor",
6
+ DbContributor: "SQL DB Contributor",
7
+ SecurityManager: "SQL Security Manager",
8
+ ManagedInstanceContributor: "SQL Managed Instance Contributor",
9
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Azure Storage RBAC built-in role constants.
3
+ */
4
+ export const StorageRoles = {
5
+ BlobDataContributor: "Storage Blob Data Contributor",
6
+ BlobDataReader: "Storage Blob Data Reader",
7
+ BlobDataOwner: "Storage Blob Data Owner",
8
+ AccountContributor: "Storage Account Contributor",
9
+ QueueDataContributor: "Storage Queue Data Contributor",
10
+ QueueDataReader: "Storage Queue Data Reader",
11
+ TableDataContributor: "Storage Table Data Contributor",
12
+ TableDataReader: "Storage Table Data Reader",
13
+ FileDataPrivilegedContributor: "Storage File Data Privileged Contributor",
14
+ FileDataPrivilegedReader: "Storage File Data Privileged Reader",
15
+ };
@@ -0,0 +1,146 @@
1
+ /**
2
+ * The native Azure read transport (#1212) — the read half of what
3
+ * `op/activities/az-apply.ts` already does for writes.
4
+ *
5
+ * Azure's observers shelled `az resource show`, once per declared entity,
6
+ * serially, and read the failure out of the CLI's stderr. The applier does
7
+ * not: `azApply` PUTs each resource at its ARM URL over `fetch`, honours an
8
+ * endpoint override, and is injectable for tests. Since `az resource show`
9
+ * returns the ARM JSON that endpoint would have returned anyway, this is
10
+ * transport only — the payload the readers normalize is unchanged, which is
11
+ * what made Azure the cheapest of the three observers to move.
12
+ *
13
+ * ## Signing
14
+ *
15
+ * Requests are unsigned, exactly like `azApply`'s. That is what makes the
16
+ * emulator lane work with no credential plumbing, and the reason this is
17
+ * scoped to floci-az rather than announced as a real-ARM read path: real ARM
18
+ * wants a bearer token. The `az` CLI path remains for a signed read until
19
+ * token acquisition lands here.
20
+ */
21
+ /** Default ARM host, matching the applier's. */
22
+ const DEFAULT_ENDPOINT = "https://management.azure.com";
23
+ /** floci-az's fixed local subscription, matching the applier's. */
24
+ const DEFAULT_SUBSCRIPTION = "00000000-0000-0000-0000-000000000001";
25
+ /** Generic ARM resource read, adequate for every top-level type chant declares. */
26
+ const DEFAULT_API_VERSION = "2021-04-01";
27
+ /** A failed read, carrying the status and ARM's own error code where it sent one. */
28
+ export class AzureReadError extends Error {
29
+ constructor(message, status, code) {
30
+ super(message);
31
+ this.status = status;
32
+ this.code = code;
33
+ this.name = "AzureReadError";
34
+ }
35
+ }
36
+ /** True when the read failed only because the resource is not there. */
37
+ export function isNotFound(err) {
38
+ return err instanceof AzureReadError && err.status === 404;
39
+ }
40
+ function isRecord(value) {
41
+ return typeof value === "object" && value !== null && !Array.isArray(value);
42
+ }
43
+ const defaultHttp = async (method, url, body, signal) => {
44
+ const res = await fetch(url, {
45
+ method,
46
+ headers: body === undefined ? undefined : { "content-type": "application/json" },
47
+ body: body === undefined ? undefined : JSON.stringify(body),
48
+ signal,
49
+ });
50
+ return { status: res.status, text: await res.text() };
51
+ };
52
+ /** The ARM URL for one resource in the group — the same shape the applier PUTs to. */
53
+ export function armResourceReadUrl(options, type, name, apiVersion = DEFAULT_API_VERSION) {
54
+ const base = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
55
+ const subscription = options.subscriptionId ?? DEFAULT_SUBSCRIPTION;
56
+ return `${base}/subscriptions/${subscription}/resourceGroups/${options.resourceGroup}/providers/${type}/${name}?api-version=${apiVersion}`;
57
+ }
58
+ /**
59
+ * ARM's error envelope is `{ error: { code, message } }`. Reading the code
60
+ * rather than the prose is the point of moving off the CLI: `ResourceNotFound`
61
+ * is a fact, "(ResourceNotFound) The Resource … was not found" is a sentence
62
+ * that changes between CLI versions.
63
+ */
64
+ function readError(status, text) {
65
+ let code;
66
+ let message = `ARM read failed with HTTP ${status}`;
67
+ try {
68
+ const body = JSON.parse(text);
69
+ const error = isRecord(body) ? body.error : undefined;
70
+ if (isRecord(error)) {
71
+ if (typeof error.code === "string")
72
+ code = error.code;
73
+ if (typeof error.message === "string")
74
+ message = error.message;
75
+ }
76
+ }
77
+ catch {
78
+ // A non-JSON body from a proxy or a gateway — the status is all there is.
79
+ }
80
+ return new AzureReadError(message, status, code);
81
+ }
82
+ /**
83
+ * GET the resource-group's resource list — the enumeration half live export
84
+ * needs (#1214). Real ARM returns envelopes (id/name/type/location/tags);
85
+ * callers wanting the full body follow up with {@link getResourceById}.
86
+ */
87
+ export async function listResources(options) {
88
+ const http = options.http ?? defaultHttp;
89
+ const base = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
90
+ const subscription = options.subscriptionId ?? DEFAULT_SUBSCRIPTION;
91
+ const url = `${base}/subscriptions/${subscription}/resourceGroups/${options.resourceGroup}/resources?api-version=${DEFAULT_API_VERSION}`;
92
+ const res = await http("GET", url, undefined, options.signal);
93
+ if (res.status >= 300)
94
+ throw readError(res.status, res.text);
95
+ try {
96
+ const body = JSON.parse(res.text);
97
+ const value = isRecord(body) ? body.value : undefined;
98
+ if (!Array.isArray(value))
99
+ throw new AzureReadError("unparseable ARM resource list", res.status);
100
+ return value.filter(isRecord);
101
+ }
102
+ catch (err) {
103
+ if (err instanceof AzureReadError)
104
+ throw err;
105
+ throw new AzureReadError("unparseable ARM resource list", res.status);
106
+ }
107
+ }
108
+ /** GET one resource by its full ARM id — the read for a list entry, nested types included. */
109
+ export async function getResourceById(options, id, apiVersion = DEFAULT_API_VERSION) {
110
+ const http = options.http ?? defaultHttp;
111
+ const base = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
112
+ const url = `${base}${id}?api-version=${apiVersion}`;
113
+ const res = await http("GET", url, undefined, options.signal);
114
+ if (res.status >= 300)
115
+ throw readError(res.status, res.text);
116
+ try {
117
+ const body = JSON.parse(res.text);
118
+ if (!isRecord(body))
119
+ throw new AzureReadError(`unparseable ARM body for ${id}`, res.status);
120
+ return body;
121
+ }
122
+ catch (err) {
123
+ if (err instanceof AzureReadError)
124
+ throw err;
125
+ throw new AzureReadError(`unparseable ARM body for ${id}`, res.status);
126
+ }
127
+ }
128
+ /** GET one resource. Throws {@link AzureReadError}; 404 means absent, which callers check with {@link isNotFound}. */
129
+ export async function getResource(options, type, name, apiVersion) {
130
+ const http = options.http ?? defaultHttp;
131
+ const url = armResourceReadUrl(options, type, name, apiVersion);
132
+ const res = await http("GET", url, undefined, options.signal);
133
+ if (res.status >= 300)
134
+ throw readError(res.status, res.text);
135
+ try {
136
+ const body = JSON.parse(res.text);
137
+ if (!isRecord(body))
138
+ throw new AzureReadError(`unparseable ARM body for ${type}/${name}`, res.status);
139
+ return body;
140
+ }
141
+ catch (err) {
142
+ if (err instanceof AzureReadError)
143
+ throw err;
144
+ throw new AzureReadError(`unparseable ARM body for ${type}/${name}`, res.status);
145
+ }
146
+ }
@@ -0,0 +1,2 @@
1
+ import { generateDocs } from "./docs.js";
2
+ await generateDocs({ verbose: true });
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Azure ARM documentation generator.
3
+ *
4
+ * Calls the core docsPipeline with Azure-specific config:
5
+ * service grouping, resource type URLs, and overview content.
6
+ *
7
+ * writeDocsSite puts the pages in the main docs site under
8
+ * docs/src/content/docs/lexicons/azure/ (chant #3993).
9
+ */
10
+ import { dirname, join } from "path";
11
+ import { fileURLToPath } from "url";
12
+ import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
13
+ const __dirname_ = dirname(fileURLToPath(import.meta.url));
14
+ const pkgDir = join(__dirname_, "..", "..");
15
+ /**
16
+ * Extract the Azure service name from an ARM resource type.
17
+ * e.g. "Microsoft.Storage/storageAccounts" → "Storage"
18
+ */
19
+ function serviceFromType(resourceType) {
20
+ const match = resourceType.match(/^Microsoft\.([^/]+)/);
21
+ return match ? match[1] : "Other";
22
+ }
23
+ const overview = `The **Azure Resource Manager** lexicon provides support for defining Azure infrastructure using chant's declarative TypeScript syntax. Resources are serialized to ARM template JSON.
24
+
25
+ This lexicon is generated from the official [Azure Resource Manager Schemas](https://github.com/Azure/azure-resource-manager-schemas) and includes coverage for commonly used resource types.
26
+
27
+ Install it with:
28
+
29
+ \`\`\`bash
30
+ npm install --save-dev @intentius/chant-lexicon-azure
31
+ \`\`\``;
32
+ const outputFormat = `The Azure lexicon serializes resources into **ARM template JSON**.
33
+
34
+ ## Building
35
+
36
+ Run \`chant build\` to produce an ARM template from your declarations:
37
+
38
+ \`\`\`bash
39
+ chant build
40
+ # Writes dist/template.json
41
+ \`\`\`
42
+
43
+ The generated template includes:
44
+
45
+ - \`$schema\` pointing to the ARM deployment template schema
46
+ - \`contentVersion: "1.0.0.0"\`
47
+ - \`parameters\` section for input parameters
48
+ - \`resources\` array with typed Azure resources
49
+ - \`outputs\` section for stack outputs
50
+
51
+ ## Deploying
52
+
53
+ Use the Azure CLI to deploy the generated template:
54
+
55
+ \`\`\`bash
56
+ az deployment group create \\
57
+ --resource-group my-rg \\
58
+ --template-file dist/template.json
59
+ \`\`\``;
60
+ const docsConfig = {
61
+ name: "azure",
62
+ displayName: "Azure Resource Manager",
63
+ description: "Typed constructors for Azure Resource Manager templates",
64
+ distDir: join(pkgDir, "dist"),
65
+ outDir: join(pkgDir, "docs"),
66
+ basePath: process.env.DOCS_BASE_PATH ?? "/chant/lexicons/azure/",
67
+ overview,
68
+ outputFormat,
69
+ serviceFromType,
70
+ // `lint-rules` below is the rules documentation; the generated `rules` table
71
+ // would duplicate it and land in no sidebar (#1312). aws, k8s, gitlab and
72
+ // github already suppress it for the same reason.
73
+ };
74
+ /**
75
+ * Generate the Azure docs site.
76
+ */
77
+ export async function generateDocs(opts) {
78
+ const result = docsPipeline(docsConfig);
79
+ writeDocsSite(docsConfig, result);
80
+ if (opts?.verbose) {
81
+ console.error(`Generated ${result.pages.size} doc pages`);
82
+ }
83
+ }
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Thin entry point for `npm run generate` in lexicon-azure.
4
+ */
5
+ import { generate, writeGeneratedFiles } from "./generate.js";
6
+ import { dirname } from "path";
7
+ import { fileURLToPath } from "url";
8
+ const result = await generate({ verbose: true });
9
+ const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
10
+ writeGeneratedFiles(result, pkgDir);
11
+ console.error(`Generated ${result.resources} resources, ${result.properties} property types, ${result.enums} enums`);
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Lexicon JSON generator — produces lexicon-azure.json with metadata for all resources.
3
+ *
4
+ * Output is a Record<string, LexiconEntry> keyed by generated class name.
5
+ */
6
+ import { armShortName } from "../spec/parse.js";
7
+ import { buildRegistry, serializeRegistry, } from "@intentius/chant/codegen/generate-registry";
8
+ /**
9
+ * Curated create-only properties for common ARM resources.
10
+ * ARM public schemas lack x-ms-mutability; this map captures
11
+ * well-known immutable properties that cannot be changed after creation.
12
+ */
13
+ const CURATED_CREATE_ONLY = {
14
+ "Microsoft.Storage/storageAccounts": ["kind", "location"],
15
+ "Microsoft.Compute/virtualMachines": ["location", "zones"],
16
+ "Microsoft.Compute/virtualMachineScaleSets": ["location", "zones"],
17
+ "Microsoft.Network/virtualNetworks": ["location"],
18
+ "Microsoft.Network/networkSecurityGroups": ["location"],
19
+ "Microsoft.Network/publicIPAddresses": ["location", "zones", "sku"],
20
+ "Microsoft.Network/loadBalancers": ["location", "sku"],
21
+ "Microsoft.Web/serverfarms": ["location"],
22
+ "Microsoft.Web/sites": ["location"],
23
+ "Microsoft.ContainerService/managedClusters": ["location", "dnsPrefix"],
24
+ "Microsoft.ContainerRegistry/registries": ["location"],
25
+ "Microsoft.Sql/servers": ["location"],
26
+ "Microsoft.Sql/servers_databases": ["location"],
27
+ "Microsoft.KeyVault/vaults": ["location"],
28
+ "Microsoft.DocumentDB/databaseAccounts": ["location", "kind"],
29
+ "Microsoft.ManagedIdentity/userAssignedIdentities": ["location"],
30
+ "Microsoft.Network/dnsZones": ["location"],
31
+ "Microsoft.Insights/components": ["location", "kind"],
32
+ "Microsoft.OperationalInsights/workspaces": ["location"],
33
+ "Microsoft.EventHub/namespaces": ["location", "sku"],
34
+ "Microsoft.ServiceBus/namespaces": ["location", "sku"],
35
+ "Microsoft.Cache/redis": ["location"],
36
+ "Microsoft.Resources/deployments": ["location"],
37
+ };
38
+ /**
39
+ * Generate the lexicon-azure.json content.
40
+ */
41
+ export function generateLexiconJSON(results, naming) {
42
+ // Adapt ArmSchemaParseResult[] to RegistryResource[]
43
+ const registryResources = results.map((r) => ({
44
+ typeName: r.resource.typeName,
45
+ attributes: r.resource.attributes,
46
+ properties: r.resource.properties,
47
+ propertyTypes: r.propertyTypes,
48
+ }));
49
+ const entries = buildRegistry(registryResources, naming, {
50
+ shortName: armShortName,
51
+ buildEntry: (resource, _tsName, attrs, propConstraints) => {
52
+ const armType = resource.typeName;
53
+ const r = results.find((res) => res.resource.typeName === armType);
54
+ const createOnly = CURATED_CREATE_ONLY[armType];
55
+ return {
56
+ resourceType: armType,
57
+ kind: "resource",
58
+ lexicon: "azure",
59
+ apiVersion: r.resource.apiVersion,
60
+ ...(attrs && { attrs }),
61
+ ...(propConstraints && { propertyConstraints: propConstraints }),
62
+ ...(r.resource.resourceLevelFields.length > 0 && {
63
+ resourceLevelFields: r.resource.resourceLevelFields,
64
+ }),
65
+ ...(r.resource.tagging && { tagging: r.resource.tagging }),
66
+ ...(createOnly && { createOnly }),
67
+ ...(r.resource.deployScopes && { deployScopes: r.resource.deployScopes }),
68
+ };
69
+ },
70
+ buildPropertyEntry: (resourceType, propertyType) => ({
71
+ resourceType: `${resourceType}.${propertyType}`,
72
+ kind: "property",
73
+ lexicon: "azure",
74
+ }),
75
+ });
76
+ return serializeRegistry(entries);
77
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * TypeScript declaration file generator — produces index.d.ts with all resource classes.
3
+ *
4
+ * Output includes:
5
+ * - Resource classes with typed constructors and readonly attributes
6
+ * - Property type classes
7
+ * - Enum union types
8
+ * - Static content (ARM intrinsics, Azure pseudo-parameters, common interfaces)
9
+ */
10
+ import { armShortName } from "../spec/parse.js";
11
+ import { propertyTypeName, extractDefName } from "./naming.js";
12
+ import { writeResourceClass, writePropertyClass, writeEnumType, } from "@intentius/chant/codegen/generate-typescript";
13
+ /**
14
+ * Generate the complete .d.ts file content.
15
+ */
16
+ export function generateTypeScriptDeclarations(results, naming) {
17
+ const lines = [];
18
+ lines.push("// Code generated by chant azure generate. DO NOT EDIT generated sections.");
19
+ const resources = [];
20
+ const properties = [];
21
+ const enums = [];
22
+ for (const r of results) {
23
+ const armType = r.resource.typeName;
24
+ const tsName = naming.resolve(armType);
25
+ if (!tsName)
26
+ continue;
27
+ // Build remap from parser property type names to resolved names
28
+ const shortName = armShortName(armType);
29
+ const remap = new Map();
30
+ for (const pt of r.propertyTypes) {
31
+ const defName = extractDefName(pt.name, shortName);
32
+ remap.set(pt.name, propertyTypeName(tsName, defName));
33
+ }
34
+ for (const e of r.enums) {
35
+ const defName = extractDefName(e.name, shortName);
36
+ remap.set(e.name, propertyTypeName(tsName, defName));
37
+ }
38
+ // Map ParsedProperty/ParsedAttribute → DtsProperty/DtsAttribute
39
+ const dtsProps = r.resource.properties.map((p) => ({
40
+ name: p.name,
41
+ type: p.tsType,
42
+ required: p.required,
43
+ description: p.description,
44
+ }));
45
+ const dtsAttrs = r.resource.attributes.map((a) => ({
46
+ name: a.name.replace(/\./g, "_"),
47
+ type: a.tsType,
48
+ }));
49
+ resources.push({ tsName, properties: dtsProps, attributes: dtsAttrs, remap });
50
+ // Alias entries
51
+ for (const alias of naming.aliases(armType)) {
52
+ resources.push({ tsName: alias, properties: dtsProps, attributes: dtsAttrs, remap });
53
+ }
54
+ const ptAliases = naming.propertyTypeAliases(armType);
55
+ for (const pt of r.propertyTypes) {
56
+ const defName = extractDefName(pt.name, shortName);
57
+ const ptName = propertyTypeName(tsName, defName);
58
+ const ptProps = pt.properties.map((p) => ({
59
+ name: p.name,
60
+ type: p.tsType,
61
+ required: p.required,
62
+ description: p.description,
63
+ }));
64
+ properties.push({ tsName: ptName, properties: ptProps, remap });
65
+ if (ptAliases) {
66
+ const aliasName = ptAliases.get(defName);
67
+ if (aliasName) {
68
+ properties.push({ tsName: aliasName, properties: ptProps, remap });
69
+ }
70
+ }
71
+ }
72
+ for (const e of r.enums) {
73
+ const defName = extractDefName(e.name, shortName);
74
+ const eName = propertyTypeName(tsName, defName);
75
+ enums.push({ tsName: eName, values: e.values });
76
+ }
77
+ }
78
+ // Sort all entries alphabetically
79
+ resources.sort((a, b) => a.tsName.localeCompare(b.tsName));
80
+ properties.sort((a, b) => a.tsName.localeCompare(b.tsName));
81
+ enums.sort((a, b) => a.tsName.localeCompare(b.tsName));
82
+ // Section 1: Resource classes
83
+ lines.push("");
84
+ lines.push("// --- Resource classes ---");
85
+ for (const re of resources) {
86
+ writeResourceClass(lines, re.tsName, re.properties, re.attributes, re.remap, "ArmResourceAttributes");
87
+ }
88
+ // Section 2: Property classes
89
+ lines.push("");
90
+ lines.push("// --- Property classes ---");
91
+ for (const pe of properties) {
92
+ writePropertyClass(lines, pe.tsName, pe.properties, pe.remap);
93
+ }
94
+ // Section 3: Enum types
95
+ if (enums.length > 0) {
96
+ lines.push("");
97
+ lines.push("// --- Enum types ---");
98
+ for (const ee of enums) {
99
+ writeEnumType(lines, ee.tsName, ee.values);
100
+ }
101
+ }
102
+ // Section 4: Static content
103
+ lines.push("");
104
+ lines.push(staticTypeScript());
105
+ lines.push("");
106
+ return lines.join("\n");
107
+ }
108
+ // --- Static content ---
109
+ function staticTypeScript() {
110
+ const lines = [];
111
+ // ARM template functions
112
+ lines.push("// --- ARM template functions ---");
113
+ lines.push("");
114
+ const intrinsics = [
115
+ ["Concat", "(...values: unknown[]): any"],
116
+ ["Format", "(format: string, ...args: unknown[]): any"],
117
+ ["If", "(condition: string, trueValue: unknown, falseValue: unknown): any"],
118
+ ["ListKeys", "(resourceId: unknown, apiVersion: string): any"],
119
+ ["Reference", "(name: string, apiVersion?: string): any"],
120
+ ["ResourceGroup", "(): any"],
121
+ ["ResourceId", "(type: string, ...names: unknown[]): any"],
122
+ ["Subscription", "(): any"],
123
+ ["UniqueString", "(...values: unknown[]): any"],
124
+ ];
125
+ intrinsics.sort((a, b) => a[0].localeCompare(b[0]));
126
+ for (const [name, sig] of intrinsics) {
127
+ lines.push(`export declare function ${name}${sig};`);
128
+ }
129
+ // Azure pseudo-parameters
130
+ lines.push("");
131
+ lines.push("// --- Azure pseudo-parameters ---");
132
+ lines.push("");
133
+ lines.push("export declare const Azure: {");
134
+ const pseudoParams = [
135
+ "DeploymentName",
136
+ "ResourceGroupId",
137
+ "ResourceGroupLocation",
138
+ "ResourceGroupName",
139
+ "SubscriptionId",
140
+ "TenantId",
141
+ ];
142
+ for (const p of pseudoParams) {
143
+ lines.push(` readonly ${p}: any;`);
144
+ }
145
+ lines.push("};");
146
+ // Type interfaces
147
+ lines.push("");
148
+ lines.push("// --- Type interfaces ---");
149
+ lines.push("");
150
+ lines.push("export interface Declarable {");
151
+ lines.push(" readonly entityType: string;");
152
+ lines.push("}");
153
+ lines.push("");
154
+ lines.push("export interface ArmResourceAttributes {");
155
+ lines.push(" DependsOn?: Declarable | Declarable[] | string | string[];");
156
+ lines.push("}");
157
+ lines.push("");
158
+ lines.push("export interface Tag {");
159
+ lines.push(" key: string;");
160
+ lines.push(" value: string;");
161
+ lines.push("}");
162
+ return lines.join("\n");
163
+ }