@intentius/chant-lexicon-azure 0.124.31 → 0.124.32

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 (117) 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.js +16598 -0
  47. package/dist/generated/runtime.js +4 -0
  48. package/dist/governance.js +144 -0
  49. package/dist/import/generator.js +140 -0
  50. package/dist/import/live-export.js +39 -0
  51. package/dist/import/parser.js +192 -0
  52. package/dist/index.js +44 -0
  53. package/dist/integrity.json +2 -2
  54. package/dist/intrinsics.js +179 -0
  55. package/dist/lint/audit-catalog.js +36 -0
  56. package/dist/lint/audit-lineage.js +71 -0
  57. package/dist/lint/post-synth/arm-refs.js +94 -0
  58. package/dist/lint/post-synth/azr010.js +45 -0
  59. package/dist/lint/post-synth/azr011.js +43 -0
  60. package/dist/lint/post-synth/azr012.js +41 -0
  61. package/dist/lint/post-synth/azr013.js +50 -0
  62. package/dist/lint/post-synth/azr014.js +49 -0
  63. package/dist/lint/post-synth/azr015.js +66 -0
  64. package/dist/lint/post-synth/azr016.js +37 -0
  65. package/dist/lint/post-synth/azr017.js +37 -0
  66. package/dist/lint/post-synth/azr018.js +42 -0
  67. package/dist/lint/post-synth/azr019.js +41 -0
  68. package/dist/lint/post-synth/azr020.js +37 -0
  69. package/dist/lint/post-synth/azr021.js +36 -0
  70. package/dist/lint/post-synth/azr022.js +39 -0
  71. package/dist/lint/post-synth/azr023.js +39 -0
  72. package/dist/lint/post-synth/azr024.js +39 -0
  73. package/dist/lint/post-synth/azr025.js +37 -0
  74. package/dist/lint/post-synth/azr026.js +38 -0
  75. package/dist/lint/post-synth/azr027.js +37 -0
  76. package/dist/lint/post-synth/azr028.js +37 -0
  77. package/dist/lint/post-synth/azr029.js +38 -0
  78. package/dist/lint/post-synth/azr030.js +44 -0
  79. package/dist/lint/post-synth/azr031.js +36 -0
  80. package/dist/lint/post-synth/azr032.js +53 -0
  81. package/dist/lint/post-synth/azr033.js +35 -0
  82. package/dist/lint/post-synth/index.js +50 -0
  83. package/dist/lint/rules/hardcoded-location.js +82 -0
  84. package/dist/lint/rules/index.js +6 -0
  85. package/dist/lint/rules/nsg-wildcard.js +44 -0
  86. package/dist/lint/rules/storage-https.js +62 -0
  87. package/dist/lsp/completions.d.ts.map +1 -1
  88. package/dist/lsp/completions.js +18 -0
  89. package/dist/lsp/hover.d.ts.map +1 -1
  90. package/dist/lsp/hover.js +44 -0
  91. package/dist/manifest.json +1 -1
  92. package/dist/op/activities/az-apply.js +563 -0
  93. package/dist/op/activities/azure.js +48 -0
  94. package/dist/op/activities/floci-az.js +37 -0
  95. package/dist/op/activities/index.js +10 -0
  96. package/dist/op/builders.js +70 -0
  97. package/dist/ownership.js +13 -0
  98. package/dist/package-cli.js +21 -0
  99. package/dist/parameter.js +13 -0
  100. package/dist/plugin.d.ts.map +1 -1
  101. package/dist/plugin.js +472 -0
  102. package/dist/pseudo.js +40 -0
  103. package/dist/serializer.js +457 -0
  104. package/dist/spec/api-versions.js +130 -0
  105. package/dist/spec/fetch.js +196 -0
  106. package/dist/spec/parse.js +308 -0
  107. package/dist/taggable.js +34 -0
  108. package/dist/validate-cli.js +16 -0
  109. package/dist/validate.js +53 -0
  110. package/package.json +8 -8
  111. package/src/codegen/package.ts +2 -2
  112. package/src/deploy-scopes.ts +2 -1
  113. package/src/lsp/completions.ts +2 -1
  114. package/src/lsp/hover.ts +2 -1
  115. package/src/plugin.ts +3 -2
  116. package/src/serializer.ts +2 -2
  117. package/src/taggable.ts +2 -2
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Runtime factory constructors — re-exported from core.
3
+ */
4
+ export { createResource, createProperty } from "@intentius/chant/runtime";
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Azure governance authoring: the desired-state config
3
+ * shape an external governance reconciler reconciles, and `landingZoneConfig()` — the
4
+ * typed authoring layer that emits it.
5
+ *
6
+ * This is deliberately NOT a composite. The evaluability rules (EVL002/004,
7
+ * #916/#952) require composites to declare a fixed set of resources, so a
8
+ * data-driven management-group tree walker cannot be one. The split mirrors
9
+ * the AWS/GCP slices (lexicons/{aws,gcp}/src/governance.ts): authoring emits
10
+ * config (this module, arbitrary cardinality); resources for greenfield
11
+ * bootstrap are the fixed-shape composites in `composites/landing-zone.ts`;
12
+ * the reconciler consumes only the config.
13
+ *
14
+ * Azure has no OrganizationRoot analog — the tenant and its root management
15
+ * group come from Entra ID, never from the resource API. Subscriptions the
16
+ * tree declares reconcile through Microsoft.Subscription/aliases (existing
17
+ * ids are placed, missing ones created from `billingScope`); aliases deploy
18
+ * at tenant scope only (#1545).
19
+ */
20
+ // ---------------------------------------------------------------------------
21
+ // Baseline guardrails (shared with the bootstrap composites)
22
+ // ---------------------------------------------------------------------------
23
+ export const DENY_CLASSIC_RESOURCES = {
24
+ description: "Classic (ASM) compute, network, and storage resources cannot be created.",
25
+ displayName: "Deny classic resources",
26
+ mode: "All",
27
+ policyRule: {
28
+ if: { field: "type", like: "Microsoft.Classic*" },
29
+ then: { effect: "deny" },
30
+ },
31
+ };
32
+ export const DENY_UNMANAGED_DISKS = {
33
+ description: "Virtual machines and scale sets must use managed disks.",
34
+ displayName: "Deny unmanaged disks",
35
+ mode: "All",
36
+ policyRule: {
37
+ if: {
38
+ anyOf: [
39
+ {
40
+ allOf: [
41
+ { field: "type", equals: "Microsoft.Compute/virtualMachines" },
42
+ { field: "Microsoft.Compute/virtualMachines/osDisk.uri", exists: "true" },
43
+ ],
44
+ },
45
+ {
46
+ allOf: [
47
+ { field: "type", equals: "Microsoft.Compute/virtualMachineScaleSets" },
48
+ {
49
+ anyOf: [
50
+ { field: "Microsoft.Compute/VirtualMachineScaleSets/osDisk.vhdContainers", exists: "true" },
51
+ { field: "Microsoft.Compute/VirtualMachineScaleSets/osdisk.imageUrl", exists: "true" },
52
+ ],
53
+ },
54
+ ],
55
+ },
56
+ ],
57
+ },
58
+ then: { effect: "deny" },
59
+ },
60
+ };
61
+ /** Allow resource creation only in `locations` ("global" is always excepted). */
62
+ export function locationRestriction(locations) {
63
+ return {
64
+ description: `Resources may only be created in [${locations.join(", ")}].`,
65
+ displayName: "Allowed locations",
66
+ mode: "Indexed",
67
+ policyRule: {
68
+ if: {
69
+ allOf: [
70
+ { field: "location", notIn: [...locations] },
71
+ { field: "location", notEquals: "global" },
72
+ ],
73
+ },
74
+ then: { effect: "deny" },
75
+ },
76
+ };
77
+ }
78
+ /**
79
+ * The built-in DeployIfNotExists policy "Configure Azure Activity logs to
80
+ * stream to specified Log Analytics workspace" — the activity-log audit
81
+ * sink is wired by assigning it, not by declaring diagnostic settings in
82
+ * every subscription (Microsoft.Insights/diagnosticSettings is not in the
83
+ * generated surface, and the assignment covers future subscriptions too).
84
+ */
85
+ export const ACTIVITY_LOG_TO_LOG_ANALYTICS_DEFINITION_ID = "/providers/Microsoft.Authorization/policyDefinitions/2465583e-4e78-4c15-b6be-a36cbc7c8b0f";
86
+ /**
87
+ * The recommended foundation management-group structure. Exported so
88
+ * callers can extend it rather than restate it.
89
+ */
90
+ export const FOUNDATION_MANAGEMENT_GROUPS = {
91
+ Security: {},
92
+ Infrastructure: {},
93
+ Sandbox: {},
94
+ Workloads: {},
95
+ };
96
+ /**
97
+ * Author the desired-state tree an external governance reconciler reconciles. Pure.
98
+ * Throws when the tree assigns a policy name with no definition; only
99
+ * policies the tree actually assigns are included in the output.
100
+ */
101
+ export function landingZoneConfig(props = {}) {
102
+ const foundation = props.foundation ?? true;
103
+ const policies = {
104
+ ...(foundation
105
+ ? { "deny-classic-resources": DENY_CLASSIC_RESOURCES, "deny-unmanaged-disks": DENY_UNMANAGED_DISKS }
106
+ : {}),
107
+ ...(props.allowedLocations?.length
108
+ ? { "location-restriction": locationRestriction(props.allowedLocations) }
109
+ : {}),
110
+ ...props.policies,
111
+ };
112
+ const managementGroups = { ...(foundation ? FOUNDATION_MANAGEMENT_GROUPS : {}), ...props.managementGroups };
113
+ const rootPolicies = [
114
+ ...(foundation ? ["deny-classic-resources", "deny-unmanaged-disks"] : []),
115
+ ...(props.allowedLocations?.length ? ["location-restriction"] : []),
116
+ ...(props.rootPolicies ?? []),
117
+ ];
118
+ const assigned = new Set(rootPolicies);
119
+ const collect = (tree) => {
120
+ for (const node of Object.values(tree)) {
121
+ for (const p of node.policies ?? [])
122
+ assigned.add(p);
123
+ if (node.children)
124
+ collect(node.children);
125
+ }
126
+ };
127
+ collect(managementGroups);
128
+ for (const name of assigned) {
129
+ if (!policies[name]) {
130
+ throw new Error(`landingZoneConfig: policy "${name}" is assigned but not defined in policies`);
131
+ }
132
+ }
133
+ return {
134
+ tenant: {
135
+ ...(rootPolicies.length ? { policies: rootPolicies } : {}),
136
+ ...(foundation ? { blockSubscriptionsLeavingTenant: true } : {}),
137
+ },
138
+ managementGroups,
139
+ policies: Object.fromEntries(Object.entries(policies).filter(([n]) => assigned.has(n))),
140
+ ...(props.activityLogWorkspaceId
141
+ ? { auditSinks: { activityLog: { workspaceId: props.activityLogWorkspaceId } } }
142
+ : {}),
143
+ };
144
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * ARM template → TypeScript code generator.
3
+ *
4
+ * Converts intermediate representation to idiomatic chant TypeScript.
5
+ */
6
+ import { loadLexiconRegistry } from "@intentius/chant/codegen/registry";
7
+ import { createRequire } from "module";
8
+ const require = createRequire(import.meta.url);
9
+ import { join } from "path";
10
+ /**
11
+ * TypeScript code generator for ARM templates.
12
+ */
13
+ export class ArmGenerator {
14
+ constructor() {
15
+ this.typeToClass = new Map();
16
+ // Was a silent catch, which left this map empty and made the import emit
17
+ // `// Unknown resource type: Microsoft.…` — indistinguishable from a
18
+ // genuine coverage gap in the lexicon. A missing registry now says so
19
+ // (#1367).
20
+ const meta = loadLexiconRegistry(join(import.meta.dirname, "../.."), "azure");
21
+ for (const [className, entry] of Object.entries(meta)) {
22
+ if (entry.kind === "resource" && !className.includes("_")) {
23
+ this.typeToClass.set(entry.resourceType, className);
24
+ }
25
+ }
26
+ }
27
+ generate(ir) {
28
+ const lines = [];
29
+ // Collect imports
30
+ const importedClasses = new Set();
31
+ const importedIntrinsics = new Set();
32
+ let needsAzure = false;
33
+ for (const resource of ir.resources) {
34
+ const cls = this.typeToClass.get(resource.type);
35
+ if (cls)
36
+ importedClasses.add(cls);
37
+ // Check for Azure pseudo-parameters in values
38
+ if (this.hasAzurePseudo(resource.properties)) {
39
+ needsAzure = true;
40
+ }
41
+ }
42
+ if (ir.parameters.length > 0) {
43
+ // Parameters would need a Parameter import from core
44
+ }
45
+ // Build import statement
46
+ const symbols = [...importedClasses].sort();
47
+ if (importedIntrinsics.size > 0) {
48
+ symbols.push(...[...importedIntrinsics].sort());
49
+ }
50
+ if (needsAzure) {
51
+ symbols.push("Azure");
52
+ }
53
+ if (symbols.length > 0) {
54
+ lines.push(`import { ${symbols.join(", ")} } from "@intentius/chant-lexicon-azure";`);
55
+ lines.push("");
56
+ }
57
+ // Generate resources
58
+ for (const resource of ir.resources) {
59
+ const cls = this.typeToClass.get(resource.type);
60
+ const varName = this.toVarName(resource.logicalId);
61
+ if (cls) {
62
+ lines.push(`export const ${varName} = new ${cls}(${this.generateProps(resource.properties, 1)});`);
63
+ }
64
+ else {
65
+ lines.push(`// Unknown resource type: ${resource.type}`);
66
+ lines.push(`// export const ${varName} = new ${resource.type}(${this.generateProps(resource.properties, 1)});`);
67
+ }
68
+ lines.push("");
69
+ }
70
+ return [
71
+ {
72
+ path: "main.ts",
73
+ content: lines.join("\n") + "\n",
74
+ },
75
+ ];
76
+ }
77
+ toVarName(name) {
78
+ // Convert to camelCase
79
+ return name.charAt(0).toLowerCase() + name.slice(1);
80
+ }
81
+ generateProps(props, depth) {
82
+ if (!props || Object.keys(props).length === 0)
83
+ return "{}";
84
+ const indent = " ".repeat(depth);
85
+ const innerIndent = " ".repeat(depth + 1);
86
+ const entries = [];
87
+ for (const [key, value] of Object.entries(props)) {
88
+ entries.push(`${innerIndent}${key}: ${this.generateValue(value, depth + 1)},`);
89
+ }
90
+ return `{\n${entries.join("\n")}\n${indent}}`;
91
+ }
92
+ generateValue(value, depth) {
93
+ if (value === null || value === undefined)
94
+ return "undefined";
95
+ if (typeof value === "string")
96
+ return JSON.stringify(value);
97
+ if (typeof value === "number" || typeof value === "boolean")
98
+ return String(value);
99
+ if (Array.isArray(value)) {
100
+ if (value.length === 0)
101
+ return "[]";
102
+ const items = value.map((v) => this.generateValue(v, depth + 1));
103
+ return `[${items.join(", ")}]`;
104
+ }
105
+ if (typeof value === "object") {
106
+ const obj = value;
107
+ // Handle intrinsic markers
108
+ if ("__intrinsic" in obj) {
109
+ return this.generateIntrinsic(obj);
110
+ }
111
+ return this.generateProps(obj, depth);
112
+ }
113
+ return String(value);
114
+ }
115
+ generateIntrinsic(obj) {
116
+ const name = obj.__intrinsic;
117
+ switch (name) {
118
+ case "ResourceGroup":
119
+ return `Azure.ResourceGroup${obj.property?.charAt(0).toUpperCase()}${obj.property?.slice(1)}`;
120
+ case "Subscription":
121
+ return `Azure.SubscriptionId`;
122
+ case "Ref":
123
+ return obj.name;
124
+ case "ResourceId":
125
+ return `ResourceId(${obj.args.map((a) => JSON.stringify(a)).join(", ")})`;
126
+ case "Reference":
127
+ return `Reference(${obj.args.map((a) => JSON.stringify(a)).join(", ")})`;
128
+ case "Concat":
129
+ return `Concat(${obj.args.map((a) => JSON.stringify(a)).join(", ")})`;
130
+ case "UniqueString":
131
+ return `UniqueString(${obj.args.map((a) => JSON.stringify(a)).join(", ")})`;
132
+ default:
133
+ return JSON.stringify(obj);
134
+ }
135
+ }
136
+ hasAzurePseudo(props) {
137
+ const json = JSON.stringify(props);
138
+ return json.includes("resourceGroup()") || json.includes("subscription()");
139
+ }
140
+ }
@@ -0,0 +1,39 @@
1
+ import { hasOwnershipMarker } from "@intentius/chant/ownership";
2
+ import { AZURE_TAG_OWNERSHIP_KEYS } from "../ownership.js";
3
+ import { ArmParser } from "./parser.js";
4
+ /**
5
+ * Map a live ARM template (from `az group export`) to full-fidelity export IR.
6
+ *
7
+ * `az group export --output json` returns an ARM template — either as a JSON
8
+ * object or, via the CLI, a JSON string. `ArmParser` already turns the template
9
+ * into `TemplateIR` — the same IR the static-import path uses — so the result
10
+ * feeds `ArmGenerator` (templateGenerator) unchanged. Pure: all I/O stays in
11
+ * the caller (`../export-resources`).
12
+ *
13
+ * Mirrors AWS `parseStackTemplate`. The one shape difference: ARM tags are a
14
+ * `Record<string,string>` map (not the `{Key,Value}[]` array CloudFormation
15
+ * uses), so the ownership filter reads `properties.tags` directly without
16
+ * `tagArrayToMap`, against the `azure-tag` channel (`chant-managed-by`).
17
+ */
18
+ export function parseExportedTemplate(templateBody, selector, owned) {
19
+ const content = typeof templateBody === "string" ? templateBody : JSON.stringify(templateBody);
20
+ const ir = new ArmParser().parse(content);
21
+ const hasSelector = selector && (selector.type !== undefined || selector.name !== undefined);
22
+ if (!hasSelector && !owned)
23
+ return ir;
24
+ return {
25
+ ...ir,
26
+ resources: ir.resources.filter((r) => {
27
+ if (selector?.type !== undefined && r.type !== selector.type)
28
+ return false;
29
+ if (selector?.name !== undefined && r.logicalId !== selector.name)
30
+ return false;
31
+ if (owned) {
32
+ const tags = r.properties.tags;
33
+ if (!hasOwnershipMarker(tags, AZURE_TAG_OWNERSHIP_KEYS))
34
+ return false;
35
+ }
36
+ return true;
37
+ }),
38
+ };
39
+ }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * ARM template JSON parser — converts ARM templates to intermediate representation.
3
+ *
4
+ * Handles ARM bracket expressions: [resourceId(...)], [reference(...)],
5
+ * [parameters(...)], [variables(...)], [concat(...)], etc.
6
+ */
7
+ import { BaseValueParser } from "@intentius/chant/import/base-parser";
8
+ /**
9
+ * ARM template parser.
10
+ */
11
+ export class ArmParser extends BaseValueParser {
12
+ // ARM expresses intrinsics as bracketed string expressions (e.g.
13
+ // "[resourceId(...)]"), not single-key objects, so there are no object-form
14
+ // intrinsics to dispatch during value walking.
15
+ dispatchIntrinsic() {
16
+ return null;
17
+ }
18
+ parse(content) {
19
+ const template = JSON.parse(content);
20
+ if (!template.resources || !Array.isArray(template.resources)) {
21
+ throw new Error("Invalid ARM template: missing resources array");
22
+ }
23
+ const parameters = [];
24
+ const resources = [];
25
+ // Parse parameters
26
+ if (template.parameters) {
27
+ for (const [name, param] of Object.entries(template.parameters)) {
28
+ const p = param;
29
+ parameters.push({
30
+ name,
31
+ type: mapArmParameterType(p.type),
32
+ description: p.metadata?.description ?? p.description,
33
+ defaultValue: p.defaultValue,
34
+ });
35
+ }
36
+ }
37
+ // Parse resources
38
+ for (const resource of template.resources) {
39
+ const r = resource;
40
+ const type = r.type;
41
+ const name = r.name;
42
+ // Collect all properties including resource-level fields
43
+ const properties = {};
44
+ // Resource-level fields
45
+ for (const field of ["location", "sku", "kind", "identity", "tags", "zones", "plan"]) {
46
+ if (r[field] !== undefined) {
47
+ properties[field] = this.parseValue(r[field]);
48
+ }
49
+ }
50
+ // Nested properties
51
+ if (r.properties && typeof r.properties === "object") {
52
+ for (const [key, value] of Object.entries(r.properties)) {
53
+ properties[key] = this.parseValue(value);
54
+ }
55
+ }
56
+ // Parse dependsOn
57
+ const dependsOn = r.dependsOn;
58
+ const deps = dependsOn?.map((d) => this.extractResourceName(d)) ?? [];
59
+ resources.push({
60
+ logicalId: name,
61
+ type,
62
+ properties,
63
+ // ResourceIR has no dedicated dependsOn field — preserve ARM dependencies in metadata.
64
+ ...(deps.length > 0 && { metadata: { dependsOn: deps } }),
65
+ });
66
+ }
67
+ return {
68
+ parameters,
69
+ resources,
70
+ metadata: {
71
+ format: "arm",
72
+ schema: template.$schema,
73
+ contentVersion: template.contentVersion,
74
+ },
75
+ };
76
+ }
77
+ /**
78
+ * Parse a value, handling ARM bracket expressions.
79
+ */
80
+ parseValue(value) {
81
+ if (typeof value === "string") {
82
+ return this.parseBracketExpression(value);
83
+ }
84
+ if (Array.isArray(value)) {
85
+ return value.map((v) => this.parseValue(v));
86
+ }
87
+ if (typeof value === "object" && value !== null) {
88
+ const result = {};
89
+ for (const [k, v] of Object.entries(value)) {
90
+ result[k] = this.parseValue(v);
91
+ }
92
+ return result;
93
+ }
94
+ return value;
95
+ }
96
+ /**
97
+ * Parse ARM bracket expressions like [resourceId(...)], [reference(...)], etc.
98
+ */
99
+ parseBracketExpression(value) {
100
+ if (!value.startsWith("[") || !value.endsWith("]"))
101
+ return value;
102
+ // Escaped bracket
103
+ if (value.startsWith("[["))
104
+ return value.slice(1);
105
+ const expr = value.slice(1, -1);
106
+ // resourceId(...)
107
+ const resourceIdMatch = expr.match(/^resourceId\((.+)\)$/);
108
+ if (resourceIdMatch) {
109
+ return { __intrinsic: "ResourceId", args: this.parseArgs(resourceIdMatch[1]) };
110
+ }
111
+ // reference(...)
112
+ const referenceMatch = expr.match(/^reference\((.+)\)$/);
113
+ if (referenceMatch) {
114
+ return { __intrinsic: "Reference", args: this.parseArgs(referenceMatch[1]) };
115
+ }
116
+ // parameters(...)
117
+ const parametersMatch = expr.match(/^parameters\('([^']+)'\)$/);
118
+ if (parametersMatch) {
119
+ return { __intrinsic: "Ref", name: parametersMatch[1] };
120
+ }
121
+ // concat(...)
122
+ const concatMatch = expr.match(/^concat\((.+)\)$/);
123
+ if (concatMatch) {
124
+ return { __intrinsic: "Concat", args: this.parseArgs(concatMatch[1]) };
125
+ }
126
+ // resourceGroup().location, resourceGroup().name, etc.
127
+ const rgMatch = expr.match(/^resourceGroup\(\)\.(\w+)$/);
128
+ if (rgMatch) {
129
+ return { __intrinsic: "ResourceGroup", property: rgMatch[1] };
130
+ }
131
+ // subscription().subscriptionId, etc.
132
+ const subMatch = expr.match(/^subscription\(\)\.(\w+)$/);
133
+ if (subMatch) {
134
+ return { __intrinsic: "Subscription", property: subMatch[1] };
135
+ }
136
+ // uniqueString(...)
137
+ const uniqueMatch = expr.match(/^uniqueString\((.+)\)$/);
138
+ if (uniqueMatch) {
139
+ return { __intrinsic: "UniqueString", args: this.parseArgs(uniqueMatch[1]) };
140
+ }
141
+ // Return raw expression as-is
142
+ return value;
143
+ }
144
+ /**
145
+ * Parse comma-separated args from a function call string.
146
+ */
147
+ parseArgs(argsStr) {
148
+ const args = [];
149
+ let depth = 0;
150
+ let current = "";
151
+ for (const char of argsStr) {
152
+ if (char === "(")
153
+ depth++;
154
+ if (char === ")")
155
+ depth--;
156
+ if (char === "," && depth === 0) {
157
+ args.push(current.trim().replace(/^'|'$/g, ""));
158
+ current = "";
159
+ }
160
+ else {
161
+ current += char;
162
+ }
163
+ }
164
+ if (current.trim()) {
165
+ args.push(current.trim().replace(/^'|'$/g, ""));
166
+ }
167
+ return args;
168
+ }
169
+ /**
170
+ * Extract a resource name from a dependsOn resourceId expression.
171
+ */
172
+ extractResourceName(dep) {
173
+ if (dep.startsWith("[")) {
174
+ // Try to extract from resourceId expression
175
+ const match = dep.match(/resourceId\([^,]+,\s*'([^']+)'\)/);
176
+ if (match)
177
+ return match[1];
178
+ }
179
+ return dep;
180
+ }
181
+ }
182
+ function mapArmParameterType(type) {
183
+ switch (type?.toLowerCase()) {
184
+ case "string": return "String";
185
+ case "int": return "Number";
186
+ case "bool": return "String";
187
+ case "array": return "CommaDelimitedList";
188
+ case "object": return "String";
189
+ case "securestring": return "String";
190
+ default: return "String";
191
+ }
192
+ }
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @intentius/chant-lexicon-azure — barrel export
3
+ *
4
+ * Azure Resource Manager lexicon for chant.
5
+ */
6
+ // Typed Op step-builder wrappers (chant #1288 Stage 2) — azApply/azDelete/
7
+ // azGroupEnsure/azGroupDelete/flociAzUp/flociAzDown with authoring-time
8
+ // types derived from this lexicon's own *Args interfaces (see
9
+ // ./op/builders.ts's module doc for why these live here rather than in
10
+ // core). Opt-in: `@intentius/chant/op`'s same-named exports are core's
11
+ // original untyped builders, unchanged.
12
+ export { azApply, azDelete, azGroupEnsure, azGroupDelete, flociAzUp, flociAzDown } from "./op/builders.js";
13
+ // --- Core ---
14
+ export { defaultTags } from "./default-tags.js";
15
+ export { deploymentScope, isDeploymentScope } from "./deploy-scopes.js";
16
+ export { azureSerializer } from "./serializer.js";
17
+ export { azurePlugin } from "./plugin.js";
18
+ export { Parameter } from "./parameter.js";
19
+ // Deep observation (#1086): the `az resource show` reader and the noise
20
+ // rules it shares with core's normalization pass.
21
+ export { observeResourcesDeepAzure, azureDeepNormalizationHooks, AZURE_READ_ONLY_NAMES, AZURE_SERVER_COMPUTED_NAMES, AZURE_SERVICE_DEFAULTS, } from "./deep-observe.js";
22
+ // --- Intrinsics ---
23
+ export { ResourceId, ResourceIdIntrinsic, Reference, ReferenceIntrinsic, Concat, ConcatIntrinsic, ResourceGroup, ResourceGroupIntrinsic, Subscription, SubscriptionIntrinsic, UniqueString, UniqueStringIntrinsic, Format, FormatIntrinsic, If, IfIntrinsic, ListKeys, ListKeysIntrinsic, } from "./intrinsics.js";
24
+ // --- Pseudo-parameters ---
25
+ export { Azure, ResourceGroupName, ResourceGroupLocation, ResourceGroupId, SubscriptionId, TenantId, DeploymentName, } from "./pseudo.js";
26
+ // --- Re-exports from core ---
27
+ export { isChildProject } from "@intentius/chant/child-project";
28
+ export { stackOutput, isStackOutput } from "@intentius/chant/stack-output";
29
+ export { LexiconOutput, output, isLexiconOutput } from "@intentius/chant/lexicon-output";
30
+ // --- Generated resource classes ---
31
+ export * from "./generated/index.js";
32
+ // --- Composites ---
33
+ export { StorageAccountSecure, VnetDefault, VmLinux, AppService, AksCluster, SqlDatabase, KeyVaultSecure, ContainerRegistrySecure, FunctionApp, ServiceBusPipeline, CosmosDatabase, ApplicationGateway, ContainerInstance, RedisCache, PrivateEndpoint, GovernanceFoundation, GovernanceBaseline, LocationRestriction, ActivityLogSink, } from "./composites/index.js";
34
+ // Azure governance authoring: the desired-state config the Azure
35
+ // external governance reconciler applies, and the typed landing-zone authoring layer.
36
+ export { landingZoneConfig, locationRestriction, DENY_CLASSIC_RESOURCES, DENY_UNMANAGED_DISKS, ACTIVITY_LOG_TO_LOG_ANALYTICS_DEFINITION_ID, FOUNDATION_MANAGEMENT_GROUPS, } from "./governance.js";
37
+ // --- RBAC role constants ---
38
+ export { StorageRoles, ComputeRoles, NetworkRoles, KeyVaultRoles, SqlRoles, ContainerRoles, AppServiceRoles, IdentityRoles, } from "./actions/index.js";
39
+ // --- Codegen pipeline ---
40
+ export { generate, writeGeneratedFiles } from "./codegen/generate.js";
41
+ export { packageLexicon } from "./codegen/package.js";
42
+ // --- Spec utilities ---
43
+ export { fetchArmSchemas } from "./spec/fetch.js";
44
+ export { parseArmSchema, armShortName, armServiceName } from "./spec/parse.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "75b76ca101cd4281f2e5ef71bf40181bc0ef256800cbe3e985a817d64de8787d",
4
+ "manifest.json": "73f94421607348da234c7b2fe2431c917da7c16edc29fa1606a5a41498acf91f",
5
5
  "meta.json": "8c7a1ea3cfaf39461d3e758fa2b0cbd70c7800fac736e56df8d14a3e07ef1840",
6
6
  "types/index.d.ts": "b20aaa3eeb957a6a5833dcbf5fd99ce1365285eafd4b78dc9383371b1a9d4b61",
7
7
  "rules/hardcoded-location.ts": "0b895449c8c94066e81721c46be24249231029fe13b471477456df5c4e45b8bf",
@@ -37,5 +37,5 @@
37
37
  "skills/chant-azure-patterns.md": "1a3bacfac612826b77332d2692a59195638db9f1b5e8ea2eda7579621d25f603",
38
38
  "skills/chant-azure-aks.md": "2d4e0098c1a22b54ffadd410564d9df0f3a04cb4eb7c6261f20ae33106e7aca8"
39
39
  },
40
- "composite": "00374ddfe2e11e4ab5f717b8d65951349635108e28e7d1c6afd177e5f31c1b2e"
40
+ "composite": "95455caf05c28b24f7081e35276586087791d81c4b2d88d516a7fd35f5d8a59c"
41
41
  }