diff --git a/packages/cdk8s-cli/package.json b/packages/cdk8s-cli/package.json index 9abad871a0..c0b7921786 100644 --- a/packages/cdk8s-cli/package.json +++ b/packages/cdk8s-cli/package.json @@ -53,7 +53,7 @@ "@types/node": "^10.17.0", "cdk8s": "0.0.0", "codemaker": "^1.14.1", - "constructs": "3.0.4", + "constructs": "3.2.34", "fs-extra": "^8.1.0", "jsii-pacmak": "^1.14.1", "jsii-srcmak": "^0.1.36", diff --git a/packages/cdk8s-plus-17/API.md b/packages/cdk8s-plus-17/API.md index d4e91c85b1..9729af5de4 100644 --- a/packages/cdk8s-plus-17/API.md +++ b/packages/cdk8s-plus-17/API.md @@ -627,7 +627,7 @@ addRules(...rules: IngressV1Beta1Rule[]): void #### protected onValidate()🔹 -Validate the current construct. +(deprecated) Validate the current construct. This method can be implemented by derived constructs in order to perform validation logic. It is called on all constructs before synthesis. diff --git a/packages/cdk8s-plus-17/package.json b/packages/cdk8s-plus-17/package.json index 9463166499..eee02cc861 100644 --- a/packages/cdk8s-plus-17/package.json +++ b/packages/cdk8s-plus-17/package.json @@ -38,16 +38,16 @@ "@typescript-eslint/eslint-plugin": "^4.3.0", "@typescript-eslint/parser": "^4.3.0", "cdk8s": "^0.0.0", - "constructs": "3.0.4", + "constructs": "3.2.34", "eslint": "^6.8.0", "eslint-import-resolver-node": "^0.3.3", "eslint-import-resolver-typescript": "^2.0.0", "eslint-plugin-import": "^2.20.2", "jest": "^26.4.2", - "jsii": "^1.9.0", - "jsii-diff": "^1.9.0", + "jsii": "^1.14.1", + "jsii-diff": "^1.14.1", "jsii-docgen": "^1.3.2", - "jsii-pacmak": "^1.9.0", + "jsii-pacmak": "^1.14.1", "json-schema": "^0.2.5", "projen": "^0.3.168", "standard-version": "^9.0.0", @@ -56,7 +56,7 @@ }, "peerDependencies": { "cdk8s": "^0.0.0", - "constructs": "^3.0.4" + "constructs": "^3.2.34" }, "dependencies": { "minimatch": "^3.0.4" diff --git a/packages/cdk8s-plus-17/src/deployment.ts b/packages/cdk8s-plus-17/src/deployment.ts index bcf0b94a00..e79c50c9c6 100644 --- a/packages/cdk8s-plus-17/src/deployment.ts +++ b/packages/cdk8s-plus-17/src/deployment.ts @@ -1,5 +1,5 @@ import { ApiObject, ApiObjectMetadataDefinition, Lazy, Names } from 'cdk8s'; -import { Construct, Node } from 'constructs'; +import { Construct } from 'constructs'; import { Resource, ResourceProps } from './base'; import { Container, ContainerProps } from './container'; import * as k8s from './imports/k8s'; @@ -124,7 +124,7 @@ export class Deployment extends Resource implements IPodTemplate { if (props.defaultSelector ?? true) { const selector = 'cdk8s.deployment'; - const matcher = Names.toLabelValue(Node.of(this).path); + const matcher = Names.toLabelValue(this); this.podMetadata.addLabel(selector, matcher); this.selectByLabel(selector, matcher); } diff --git a/packages/cdk8s-plus-17/test/__snapshots__/config-map.test.ts.snap b/packages/cdk8s-plus-17/test/__snapshots__/config-map.test.ts.snap index b96f6ce442..754d0c3d9c 100644 --- a/packages/cdk8s-plus-17/test/__snapshots__/config-map.test.ts.snap +++ b/packages/cdk8s-plus-17/test/__snapshots__/config-map.test.ts.snap @@ -9,7 +9,7 @@ Array [ }, "kind": "ConfigMap", "metadata": Object { - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", }, }, ] @@ -25,7 +25,7 @@ Array [ }, "kind": "ConfigMap", "metadata": Object { - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", }, }, ] @@ -41,7 +41,7 @@ Array [ }, "kind": "ConfigMap", "metadata": Object { - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", }, }, ] @@ -56,7 +56,7 @@ Array [ }, "kind": "ConfigMap", "metadata": Object { - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", }, }, ] @@ -72,7 +72,7 @@ Array [ }, "kind": "ConfigMap", "metadata": Object { - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", }, }, ] diff --git a/packages/cdk8s-plus-17/test/config-map.test.ts b/packages/cdk8s-plus-17/test/config-map.test.ts index 8b04ae0e66..e3aa685ebb 100644 --- a/packages/cdk8s-plus-17/test/config-map.test.ts +++ b/packages/cdk8s-plus-17/test/config-map.test.ts @@ -25,7 +25,7 @@ test('minimal', () => { apiVersion: 'v1', kind: 'ConfigMap', metadata: { - name: 'test-my-config-map-91419662', + name: 'test-my-config-map-c8eaefa4', }, }, ]); @@ -53,7 +53,7 @@ test('with data', () => { key2: 'bar', }, metadata: { - name: 'test-my-config-map-91419662', + name: 'test-my-config-map-c8eaefa4', }, }, ]); @@ -81,7 +81,7 @@ test('with binaryData', () => { key2: 'bar', }, metadata: { - name: 'test-my-config-map-91419662', + name: 'test-my-config-map-c8eaefa4', }, }, ]); @@ -115,7 +115,7 @@ test('with binaryData and data', () => { key2: 'bar', }, metadata: { - name: 'test-my-config-map-91419662', + name: 'test-my-config-map-c8eaefa4', }, }, ]); @@ -174,7 +174,7 @@ test('addData()/addBinaryDataq() can be used to add data', () => { }, kind: 'ConfigMap', metadata: { - name: 'test-my-config-map-91419662', + name: 'test-my-config-map-c8eaefa4', }, }, ]); diff --git a/packages/cdk8s-plus-17/test/deployment.test.ts b/packages/cdk8s-plus-17/test/deployment.test.ts index 377b648c46..b33d10eba3 100644 --- a/packages/cdk8s-plus-17/test/deployment.test.ts +++ b/packages/cdk8s-plus-17/test/deployment.test.ts @@ -19,7 +19,7 @@ test('A label selector is automatically allocated', () => { const deployment = new kplus.Deployment(chart, 'Deployment'); deployment.addContainer({ image: 'foobar' }); - const expectedValue = 'test-Deployment-9e0110cd'; + const expectedValue = 'test-Deployment-c83f5e59'; const expectedSelector = { 'cdk8s.deployment': expectedValue }; // assert the k8s spec has it. @@ -94,7 +94,7 @@ test('Can be exposed as via service', () => { const spec = Testing.synth(chart)[1].spec; expect(spec.type).toEqual('LoadBalancer'); - expect(spec.selector).toEqual({ 'cdk8s.deployment': 'test-Deployment-9e0110cd' }); + expect(spec.selector).toEqual({ 'cdk8s.deployment': 'test-Deployment-c83f5e59' }); expect(spec.ports![0].port).toEqual(9200); expect(spec.ports![0].targetPort).toEqual(9300); @@ -149,7 +149,7 @@ test('Expose can set service and port details', () => { expect(srv.metadata.name).toEqual('test-srv'); expect(spec.type).toEqual('ClusterIP'); expect(spec.selector).toEqual({ - 'cdk8s.deployment': 'test-Deployment-9e0110cd', + 'cdk8s.deployment': 'test-Deployment-c83f5e59', }); expect(spec.ports![0].port).toEqual(9200); expect(spec.ports![0].targetPort).toEqual(9500); diff --git a/packages/cdk8s-plus-17/test/ingress-v1beta1.test.ts b/packages/cdk8s-plus-17/test/ingress-v1beta1.test.ts index f70a5ab575..2503ef11aa 100644 --- a/packages/cdk8s-plus-17/test/ingress-v1beta1.test.ts +++ b/packages/cdk8s-plus-17/test/ingress-v1beta1.test.ts @@ -24,7 +24,7 @@ describe('IngressBackend', () => { // THEN expect(IngressV1Beta1Backend.fromService(service)._toKube()).toEqual({ - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 8899, }); }); @@ -61,7 +61,7 @@ describe('IngressBackend', () => { // THEN expect(IngressV1Beta1Backend.fromService(service, { port: 6011 })._toKube()).toEqual({ - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 6011, }); }); @@ -78,7 +78,7 @@ describe('IngressBackend', () => { // THEN expect(IngressV1Beta1Backend.fromService(service, { port: 8899 })._toKube()).toEqual({ - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 8899, }); }); @@ -130,10 +130,10 @@ describe('Ingress', () => { { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', - metadata: { name: 'test-my-ingress-e859c4c6' }, + metadata: { name: 'test-my-ingress-c8135042' }, spec: { backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -155,10 +155,10 @@ describe('Ingress', () => { { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', - metadata: { name: 'test-my-ingress-e859c4c6' }, + metadata: { name: 'test-my-ingress-c8135042' }, spec: { backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -182,7 +182,7 @@ describe('Ingress', () => { { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', - metadata: { name: 'test-my-ingress-e859c4c6' }, + metadata: { name: 'test-my-ingress-c8135042' }, spec: { rules: [{ host: 'my.host', @@ -190,7 +190,7 @@ describe('Ingress', () => { paths: [ { backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -219,7 +219,7 @@ describe('Ingress', () => { { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', - metadata: { name: 'test-my-ingress-e859c4c6' }, + metadata: { name: 'test-my-ingress-c8135042' }, spec: { rules: [ { @@ -229,14 +229,14 @@ describe('Ingress', () => { { path: '/bar', backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, { path: '/foo', backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -249,14 +249,14 @@ describe('Ingress', () => { paths: [ { backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, { path: '/', backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -284,7 +284,7 @@ describe('Ingress', () => { { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', - metadata: { name: 'test-my-ingress-e859c4c6' }, + metadata: { name: 'test-my-ingress-c8135042' }, spec: { rules: [ { @@ -293,14 +293,14 @@ describe('Ingress', () => { { path: '/foo', backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, { path: '/foo/bar', backend: { - serviceName: 'test-my-service-72ba846b', + serviceName: 'test-my-service-c8493104', servicePort: 80, }, }, @@ -331,13 +331,13 @@ describe('Ingress', () => { }); // THEN - const expectedBackend = { serviceName: 'test-my-service-72ba846b', servicePort: 4000 }; + const expectedBackend = { serviceName: 'test-my-service-c8493104', servicePort: 4000 }; expect(Testing.synth(chart).filter(x => x.kind === 'Ingress')).toEqual([ { apiVersion: 'networking.k8s.io/v1beta1', kind: 'Ingress', metadata: { - name: 'test-my-ingress-e859c4c6', + name: 'test-my-ingress-c8135042', }, spec: { backend: expectedBackend, diff --git a/packages/cdk8s-plus-17/test/secret.test.ts b/packages/cdk8s-plus-17/test/secret.test.ts index 602f64e719..bbadd80cf3 100644 --- a/packages/cdk8s-plus-17/test/secret.test.ts +++ b/packages/cdk8s-plus-17/test/secret.test.ts @@ -1,27 +1,27 @@ -import { Testing, ApiObject } from 'cdk8s'; -import { Node } from 'constructs'; -import * as kplus from '../src'; +import { Testing, ApiObject } from "cdk8s"; +import { Node } from "constructs"; +import * as kplus from "../src"; -test('defaultChild', () => { +test("defaultChild", () => { const chart = Testing.chart(); - const defaultChild = Node.of(new kplus.Secret(chart, 'Secret')).defaultChild as ApiObject; - - expect(defaultChild.kind).toEqual('Secret'); + const defaultChild = Node.of(new kplus.Secret(chart, "Secret")) + .defaultChild as ApiObject; + expect(defaultChild.kind).toEqual("Secret"); }); -test('Can be imported from secret name', () => { - const secret = kplus.Secret.fromSecretName('secret'); +test("Can be imported from secret name", () => { + const secret = kplus.Secret.fromSecretName("secret"); - expect(secret.name).toEqual('secret'); + expect(secret.name).toEqual("secret"); }); -test('Can add data to new secrets', () => { +test("Can add data to new secrets", () => { const chart = Testing.chart(); - const secret = new kplus.Secret(chart, 'Secret'); - secret.addStringData('key', 'value'); + const secret = new kplus.Secret(chart, "Secret"); + secret.addStringData("key", "value"); expect(Testing.synth(chart)).toMatchInlineSnapshot(` Array [ @@ -29,7 +29,7 @@ test('Can add data to new secrets', () => { "apiVersion": "v1", "kind": "Secret", "metadata": Object { - "name": "test-secret-17f996fa", + "name": "test-secret-c837fa76", }, "stringData": Object { "key": "value", diff --git a/packages/cdk8s-plus-17/test/service-account.test.ts b/packages/cdk8s-plus-17/test/service-account.test.ts index 8d74ad8f45..76adf6f5cc 100644 --- a/packages/cdk8s-plus-17/test/service-account.test.ts +++ b/packages/cdk8s-plus-17/test/service-account.test.ts @@ -1,22 +1,23 @@ -import { Testing, ApiObject } from 'cdk8s'; -import { Node } from 'constructs'; -import * as kplus from '../src'; +import { Testing, ApiObject } from "cdk8s"; +import { Node } from "constructs"; +import * as kplus from "../src"; -test('defaultChild', () => { +test("defaultChild", () => { const chart = Testing.chart(); - const defaultChild = Node.of(new kplus.ServiceAccount(chart, 'ServiceAccount')).defaultChild as ApiObject; - - expect(defaultChild.kind).toEqual('ServiceAccount'); + const defaultChild = Node.of( + new kplus.ServiceAccount(chart, "ServiceAccount") + ).defaultChild as ApiObject; + expect(defaultChild.kind).toEqual("ServiceAccount"); }); -test('minimal definition', () => { +test("minimal definition", () => { // GIVEN const chart = Testing.chart(); // WHEN - new kplus.ServiceAccount(chart, 'my-service-account'); + new kplus.ServiceAccount(chart, "my-service-account"); // THEN expect(Testing.synth(chart)).toMatchInlineSnapshot(` @@ -25,28 +26,28 @@ test('minimal definition', () => { "apiVersion": "v1", "kind": "ServiceAccount", "metadata": Object { - "name": "test-my-service-account-a5be5a3b", + "name": "test-my-service-account-c84bb46b", }, }, ] `); }); -test('secrets can be added to the service account', () => { +test("secrets can be added to the service account", () => { // GIVEN const chart = Testing.chart(); - const secret1 = kplus.Secret.fromSecretName('my-secret-1'); - const secret2 = kplus.Secret.fromSecretName('my-secret-2'); + const secret1 = kplus.Secret.fromSecretName("my-secret-1"); + const secret2 = kplus.Secret.fromSecretName("my-secret-2"); // WHEN - const sa = new kplus.ServiceAccount(chart, 'my-service-account', { - secrets: [secret1], + const sa = new kplus.ServiceAccount(chart, "my-service-account", { + secrets: [secret1] }); sa.addSecret(secret2); // THEN const manifest = Testing.synth(chart); - expect(manifest[0]?.secrets[0]).toStrictEqual({ name: 'my-secret-1' }); - expect(manifest[0]?.secrets[1]).toStrictEqual({ name: 'my-secret-2' }); + expect(manifest[0]?.secrets[0]).toStrictEqual({ name: "my-secret-1" }); + expect(manifest[0]?.secrets[1]).toStrictEqual({ name: "my-secret-2" }); }); diff --git a/packages/cdk8s-plus-17/test/service.test.ts b/packages/cdk8s-plus-17/test/service.test.ts index 2e4821587e..a82a47bf72 100644 --- a/packages/cdk8s-plus-17/test/service.test.ts +++ b/packages/cdk8s-plus-17/test/service.test.ts @@ -98,7 +98,7 @@ test('Can associate a deployment with an existing service', () => { service.addDeployment(deployment, 1122); - const expectedSelector = { 'cdk8s.deployment': 'test-dep-b18049c6' }; + const expectedSelector = { 'cdk8s.deployment': 'test-dep-c8cc9f8f' }; const deploymentSpec = Testing.synth(chart)[1].spec; const serviceSpec = Testing.synth(chart)[0].spec; diff --git a/packages/cdk8s-plus-17/test/volume.test.ts b/packages/cdk8s-plus-17/test/volume.test.ts index e2072f14dc..4ac94c2499 100644 --- a/packages/cdk8s-plus-17/test/volume.test.ts +++ b/packages/cdk8s-plus-17/test/volume.test.ts @@ -16,10 +16,10 @@ describe('fromConfigMap', () => { "configMap": Object { "defaultMode": undefined, "items": undefined, - "name": "test-my-config-map-91419662", + "name": "test-my-config-map-c8eaefa4", "optional": undefined, }, - "name": "configmap-test-my-config-map-91419662", + "name": "configmap-test-my-config-map-c8eaefa4", } `); }); @@ -36,9 +36,7 @@ describe('fromConfigMap', () => { // THEN expect(vol._toKube().name).toBe('filesystem'); - expect(vol._toKube().configMap?.name).toBe( - 'test-my-config-map-91419662', - ); + expect(vol._toKube().configMap?.name).toBe('test-my-config-map-c8eaefa4'); }); test('default mode', () => { diff --git a/packages/cdk8s/API.md b/packages/cdk8s/API.md index b99c03af86..c52b513859 100644 --- a/packages/cdk8s/API.md +++ b/packages/cdk8s/API.md @@ -31,6 +31,7 @@ Name|Description [ChartProps](#cdk8s-chartprops)|*No description* [HelmProps](#cdk8s-helmprops)|Options for `Helm`. [IncludeProps](#cdk8s-includeprops)|*No description* +[NameOptions](#cdk8s-nameoptions)|Options for name generation. [SizeConversionOptions](#cdk8s-sizeconversionoptions)|Options for how to convert time to a different unit. [TimeConversionOptions](#cdk8s-timeconversionoptions)|Options for how to convert time to a different unit. @@ -955,7 +956,7 @@ Utilities for generating unique and stable names. ### Methods -#### *static* toDnsLabel(path, maxLen?)🔹 +#### *static* toDnsLabel(scope, options?)🔹 Generates a unique and stable name compatible DNS_LABEL from RFC-1123 from a path. @@ -975,16 +976,19 @@ Note that if the total length is longer than 63 characters, we will trim the first components since the last components usually encode more meaning. ```ts -static toDnsLabel(path: string, maxLen?: number): string +static toDnsLabel(scope: Construct, options?: NameOptions): string ``` -* **path** (string) a path to a node (components separated by "/"). -* **maxLen** (number) maximum allowed length for name. +* **scope** ([Construct](#constructs-construct)) The construct for which to render the DNS label. +* **options** ([NameOptions](#cdk8s-nameoptions)) Name options. + * **delimiter** (string) Delimiter to use between components. __*Default*__: "-" + * **extra** (Array) Extra components to include in the name. __*Default*__: [] use the construct path components + * **maxLen** (number) Maximum allowed length for the name. __*Default*__: 63 __Returns__: * string -#### *static* toLabelValue(path, delim?, maxLen?)🔹 +#### *static* toLabelValue(scope, options?)🔹 Generates a unique and stable name compatible label key name segment and label value from a path. @@ -1006,12 +1010,14 @@ Note that if the total length is longer than 63 characters, we will trim the first components since the last components usually encode more meaning. ```ts -static toLabelValue(path: string, delim?: string, maxLen?: number): string +static toLabelValue(scope: Construct, options?: NameOptions): string ``` -* **path** (string) a path to a node (components separated by "/"). -* **delim** (string) a delimiter to separates components. -* **maxLen** (number) maximum allowed length for name. +* **scope** ([Construct](#constructs-construct)) The construct for which to render the DNS label. +* **options** ([NameOptions](#cdk8s-nameoptions)) Name options. + * **delimiter** (string) Delimiter to use between components. __*Default*__: "-" + * **extra** (Array) Extra components to include in the name. __*Default*__: [] use the construct path components + * **maxLen** (number) Maximum allowed length for the name. __*Default*__: 63 __Returns__: * string @@ -1386,6 +1392,21 @@ Name | Type | Description +## struct NameOptions 🔹 + + +Options for name generation. + + + +Name | Type | Description +-----|------|------------- +**delimiter**?🔹 | string | Delimiter to use between components.
__*Default*__: "-" +**extra**?🔹 | Array | Extra components to include in the name.
__*Default*__: [] use the construct path components +**maxLen**?🔹 | number | Maximum allowed length for the name.
__*Default*__: 63 + + + ## struct SizeConversionOptions 🔹 diff --git a/packages/cdk8s/package.json b/packages/cdk8s/package.json index e591c44e6f..d4a0324282 100644 --- a/packages/cdk8s/package.json +++ b/packages/cdk8s/package.json @@ -38,16 +38,16 @@ "@types/yaml": "^1.2.0", "@typescript-eslint/eslint-plugin": "^4.3.0", "@typescript-eslint/parser": "^4.3.0", - "constructs": "3.0.4", + "constructs": "3.2.34", "eslint": "^6.8.0", "eslint-import-resolver-node": "^0.3.3", "eslint-import-resolver-typescript": "^2.0.0", "eslint-plugin-import": "^2.20.2", "jest": "^26.4.2", - "jsii": "^1.9.0", - "jsii-diff": "^1.9.0", + "jsii": "^1.14.1", + "jsii-diff": "^1.14.1", "jsii-docgen": "^1.3.2", - "jsii-pacmak": "^1.9.0", + "jsii-pacmak": "^1.14.1", "json-schema": "^0.2.5", "json-schema-to-typescript": "^8.0.1", "projen": "^0.3.167", @@ -56,7 +56,7 @@ "typescript": "^3.9.5" }, "peerDependencies": { - "constructs": "^3.0.4" + "constructs": "^3.2.34" }, "dependencies": { "fast-json-patch": "^3.0.0-1", @@ -200,4 +200,4 @@ "rootDir": "src" } } -} +} \ No newline at end of file diff --git a/packages/cdk8s/src/app.ts b/packages/cdk8s/src/app.ts index 8bc4685a28..50a0901d1b 100644 --- a/packages/cdk8s/src/app.ts +++ b/packages/cdk8s/src/app.ts @@ -90,7 +90,7 @@ export class App extends Construct { // the necessary operations. We do however want to preserve the distributed validation. validate(this); - const simpleManifestNamer = (chart: Chart) => `${Names.toDnsLabel(Node.of(chart).path)}.k8s.yaml`; + const simpleManifestNamer = (chart: Chart) => `${Names.toDnsLabel(chart)}.k8s.yaml`; const manifestNamer = hasDependantCharts ? (chart: Chart) => `${index.toString().padStart(4, '0')}-${simpleManifestNamer(chart)}` : simpleManifestNamer; const charts: IConstruct[] = new DependencyGraph(Node.of(this)).topology().filter(x => x instanceof Chart); diff --git a/packages/cdk8s/src/chart.ts b/packages/cdk8s/src/chart.ts index efc461060d..59afb27a24 100644 --- a/packages/cdk8s/src/chart.ts +++ b/packages/cdk8s/src/chart.ts @@ -86,7 +86,7 @@ export class Chart extends Construct { * @param apiObject The API object to generate a name for. */ public generateObjectName(apiObject: ApiObject) { - return Names.toDnsLabel(Node.of(apiObject).path); + return Names.toDnsLabel(apiObject); } /** diff --git a/packages/cdk8s/src/helm.ts b/packages/cdk8s/src/helm.ts index 56e243b875..f69f62c1f0 100644 --- a/packages/cdk8s/src/helm.ts +++ b/packages/cdk8s/src/helm.ts @@ -2,7 +2,7 @@ import * as cp from 'child_process'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { Construct, Node } from 'constructs'; +import { Construct } from 'constructs'; import * as yaml from 'yaml'; import { Include } from './include'; import { Names } from './names'; @@ -81,8 +81,8 @@ export class Helm extends Include { } // release name - const cpath = [Node.of(scope).path, id].join(Node.PATH_SEP); - const releaseName = props.releaseName ?? Names.toDnsLabel(cpath, 53); // constraints: https://github.com/helm/helm/issues/6006 + // constraints: https://github.com/helm/helm/issues/6006 + const releaseName = props.releaseName ?? Names.toDnsLabel(scope, { maxLen: 53, extra: [id] }); args.push(releaseName); // chart diff --git a/packages/cdk8s/src/names.ts b/packages/cdk8s/src/names.ts index dd46a0473d..9da01e1163 100644 --- a/packages/cdk8s/src/names.ts +++ b/packages/cdk8s/src/names.ts @@ -1,11 +1,34 @@ import * as crypto from 'crypto'; +import { Construct, Node } from 'constructs'; -const MAX_DNS_NAME_LEN = 63; +const MAX_LEN = 63; const VALIDATE = /^[0-9a-z-]+$/; -const MAX_LABEL_VALUE_LEN = 63; const VALIDATE_LABEL_VALUE = /^(([0-9a-zA-Z][0-9a-zA-Z-_.]*)?[0-9a-zA-Z])?$/; const HASH_LEN = 8; +/** + * Options for name generation. + */ +export interface NameOptions { + /** + * Maximum allowed length for the name. + * @default 63 + */ + readonly maxLen?: number; + + /** + * Extra components to include in the name. + * @default [] use the construct path components + */ + readonly extra?: string[]; + + /** + * Delimiter to use between components. + * @default "-" + */ + readonly delimiter?: string; +} + /** * Utilities for generating unique and stable names. */ @@ -31,17 +54,23 @@ export class Names { * * @link https://tools.ietf.org/html/rfc1123 * - * @param path a path to a node (components separated by "/") - * @param maxLen maximum allowed length for name + * @param scope The construct for which to render the DNS label + * @param options Name options * @throws if any of the components do not adhere to naming constraints or * length. */ - public static toDnsLabel(path: string, maxLen = MAX_DNS_NAME_LEN) { + public static toDnsLabel(scope: Construct, options: NameOptions = { }) { + const maxLen = options.maxLen ?? MAX_LEN; + const delim = options.delimiter ?? '-'; + if (maxLen < HASH_LEN) { throw new Error(`minimum max length for object names is ${HASH_LEN} (required for hash)`); } - let components = path.split('/'); + const node = Node.of(scope); + + let components = node.path.split('/'); + components.push(...options.extra ?? []); // special case: if we only have one component in our path and it adheres to DNS_NAME, we don't decorate it if (components.length === 1 && VALIDATE.test(components[0]) && components[0].length <= maxLen) { @@ -50,10 +79,9 @@ export class Names { // okay, now we need to normalize all components to adhere to DNS_NAME and append the hash of the full path. components = components.map(c => normalizeToDnsName(c, maxLen)); + components.push(calcHash(node, HASH_LEN)); - components.push(calcHash(path, HASH_LEN)); - - return toHumanForm(components, '-', maxLen); + return toHumanForm(components, delim, maxLen); } /** @@ -79,13 +107,15 @@ export class Names { * * @link https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set * - * @param path a path to a node (components separated by "/") - * @param delim a delimiter to separates components - * @param maxLen maximum allowed length for name + * @param scope The construct for which to render the DNS label + * @param options Name options * @throws if any of the components do not adhere to naming constraints or * length. */ - public static toLabelValue(path: string, delim: string = '-', maxLen: number = MAX_LABEL_VALUE_LEN) { + public static toLabelValue(scope: Construct, options: NameOptions = {}) { + const maxLen = options.maxLen ?? MAX_LEN; + const delim = options.delimiter ?? '-'; + if (maxLen < HASH_LEN) { throw new Error(`minimum max length for label is ${HASH_LEN} (required for hash)`); } @@ -94,7 +124,9 @@ export class Names { throw new Error('delim should not contain "[^0-9a-zA-Z-_.]"'); } - let components = path.split('/'); + const node = Node.of(scope); + let components = node.path.split('/'); + components.push(...options.extra ?? []); // special case: if we only have one component in our path and it adheres to DNS_NAME, we don't decorate it if (components.length === 1 && VALIDATE_LABEL_VALUE.test(components[0]) && components[0].length <= maxLen) { @@ -103,8 +135,7 @@ export class Names { // okay, now we need to normalize all components to adhere to label and append the hash of the full path. components = components.map(c => normalizeToLabelValue(c, maxLen)); - - components.push(calcHash(path, HASH_LEN)); + components.push(calcHash(node, HASH_LEN)); const result = toHumanForm(components, delim, maxLen); @@ -149,14 +180,18 @@ function normalizeToDnsName(c: string, maxLen: number) { .substr(0, maxLen); // trim to maxLength } +function calcHash(node: Node, maxLen: number) { + if (process.env.CDK8S_LEGACY_HASH) { + const hash = crypto.createHash('sha256'); + hash.update(node.path); + return hash.digest('hex').slice(0, maxLen); + } + + return node.addr.substring(0, HASH_LEN); +} + function normalizeToLabelValue(c: string, maxLen: number) { return c .replace(/[^0-9a-zA-Z-_.]/g, '') // remove non-allowed characters .substr(0, maxLen); // trim to maxLength } - -function calcHash(path: string, maxLen: number) { - const hash = crypto.createHash('sha256'); - hash.update(path); - return hash.digest('hex').slice(0, maxLen); -} \ No newline at end of file diff --git a/packages/cdk8s/test/__snapshots__/api-object.test.ts.snap b/packages/cdk8s/test/__snapshots__/api-object.test.ts.snap index b703f1670d..bb62f9b2c4 100644 --- a/packages/cdk8s/test/__snapshots__/api-object.test.ts.snap +++ b/packages/cdk8s/test/__snapshots__/api-object.test.ts.snap @@ -9,7 +9,7 @@ Array [ }, "kind": "ResourceType", "metadata": Object { - "name": "test-3953b2d0", + "name": "test-c8c5facf", }, }, ] @@ -21,7 +21,7 @@ Array [ "apiVersion": "v1", "kind": "ResourceType", "metadata": Object { - "name": "test-3953b2d0", + "name": "test-c8c5facf", }, "spec": Object { "prop1": "hello", @@ -51,7 +51,7 @@ Array [ "apiVersion": "v1", "kind": "MyResource", "metadata": Object { - "name": "test-my-2998ce93", + "name": "test-my-c8487bf7", }, }, ] @@ -63,7 +63,7 @@ Array [ "apiVersion": "v1", "kind": "MyResource", "metadata": Object { - "name": "test-my-2998ce93", + "name": "test-my-c8487bf7", }, "spec": Object { "firstProperty": "hello", @@ -82,14 +82,14 @@ Array [ "apiVersion": "v1", "kind": "MyResource", "metadata": Object { - "name": "test-my-2998ce93", + "name": "test-my-c8487bf7", }, }, Object { "apiVersion": "v1", "kind": "MyResource", "metadata": Object { - "name": "test-scope-my-eddbdbb2", + "name": "test-scope-my-c8fafaf7", }, }, ] diff --git a/packages/cdk8s/test/__snapshots__/chart.test.ts.snap b/packages/cdk8s/test/__snapshots__/chart.test.ts.snap index 77369993a9..94e52213cf 100644 --- a/packages/cdk8s/test/__snapshots__/chart.test.ts.snap +++ b/packages/cdk8s/test/__snapshots__/chart.test.ts.snap @@ -8,35 +8,35 @@ Array [ "apiVersion": "v1", "kind": "Resource1", "metadata": Object { - "name": "test-resource1-2b59e3b8", + "name": "test-resource1-c85cb0fc", }, }, Object { "apiVersion": "v1", "kind": "Resource2", "metadata": Object { - "name": "test-resource2-22077398", + "name": "test-resource2-c8c6bd27", }, }, Object { "apiVersion": "v1", "kind": "Resource3", "metadata": Object { - "name": "test-resource3-365bba40", + "name": "test-resource3-c8ccc739", }, }, Object { "apiVersion": "v1", "kind": "Resource1", "metadata": Object { - "name": "test-scope-resource1-3d54e80a", + "name": "test-scope-resource1-c84ac5c2", }, }, Object { "apiVersion": "v1", "kind": "Resource2", "metadata": Object { - "name": "test-scope-resource2-e1b938d2", + "name": "test-scope-resource2-c889750d", }, }, ] @@ -48,14 +48,14 @@ Array [ "apiVersion": "v1", "kind": "Kind1", "metadata": Object { - "name": "chart-obj1-f2e469b6", + "name": "chart-obj1-c80aa35c", }, }, Object { "apiVersion": "v1", "kind": "Kind2", "metadata": Object { - "name": "chart-obj2-e10626fd", + "name": "chart-obj2-c8016fab", }, }, ] @@ -67,7 +67,7 @@ Array [ "apiVersion": "v1", "kind": "Resource1", "metadata": Object { - "name": "test-resource1-2b59e3b8", + "name": "test-resource1-c85cb0fc", }, "spec": Object { "foo": 123, diff --git a/packages/cdk8s/test/__snapshots__/helm.test.ts.snap b/packages/cdk8s/test/__snapshots__/helm.test.ts.snap index 68233d4c33..e6e5ca74cd 100644 --- a/packages/cdk8s/test/__snapshots__/helm.test.ts.snap +++ b/packages/cdk8s/test/__snapshots__/helm.test.ts.snap @@ -7,13 +7,13 @@ Array [ "kind": "ServiceAccount", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, }, Object { @@ -21,13 +21,13 @@ Array [ "kind": "Service", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, "spec": Object { "ports": Array [ @@ -39,7 +39,7 @@ Array [ }, ], "selector": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, "type": "ClusterIP", @@ -50,26 +50,26 @@ Array [ "kind": "Deployment", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, "spec": Object { "replicas": 1, "selector": Object { "matchLabels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, }, "template": Object { "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, }, @@ -103,7 +103,7 @@ Array [ }, ], "securityContext": Object {}, - "serviceAccountName": "test-sample-00742e24-helm-sample", + "serviceAccountName": "test-sample-c8e2763d-helm-sample", }, }, }, @@ -118,13 +118,13 @@ Array [ "kind": "ServiceAccount", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, }, Object { @@ -132,13 +132,13 @@ Array [ "kind": "Service", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, "spec": Object { "ports": Array [ @@ -150,7 +150,7 @@ Array [ }, ], "selector": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, "type": "ClusterIP", @@ -161,26 +161,26 @@ Array [ "kind": "Deployment", "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/managed-by": "Helm", "app.kubernetes.io/name": "helm-sample", "app.kubernetes.io/version": "1.16.0", "helm.sh/chart": "helm-sample-0.1.0", }, - "name": "test-sample-00742e24-helm-sample", + "name": "test-sample-c8e2763d-helm-sample", }, "spec": Object { "replicas": 889, "selector": Object { "matchLabels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, }, "template": Object { "metadata": Object { "labels": Object { - "app.kubernetes.io/instance": "test-sample-00742e24", + "app.kubernetes.io/instance": "test-sample-c8e2763d", "app.kubernetes.io/name": "helm-sample", }, }, @@ -217,7 +217,7 @@ Array [ "selectMe": "boomboom", }, "securityContext": Object {}, - "serviceAccountName": "test-sample-00742e24-helm-sample", + "serviceAccountName": "test-sample-c8e2763d-helm-sample", }, }, }, diff --git a/packages/cdk8s/test/api-object.test.ts b/packages/cdk8s/test/api-object.test.ts index 5d1a1270ba..e7e6d8bb7a 100644 --- a/packages/cdk8s/test/api-object.test.ts +++ b/packages/cdk8s/test/api-object.test.ts @@ -180,14 +180,14 @@ test('default namespace can be defined at the chart level', () => { kind: 'Kind1', metadata: { - name: 'chart-group1-obj1-b4b7a9d0', + name: 'chart-group1-obj1-c885aeec', namespace: 'ns1', }, }, { apiVersion: 'v2', kind: 'Kind2', metadata: { - name: 'chart-group1-obj2-3cdc9d22', + name: 'chart-group1-obj2-c81931d8', namespace: 'foobar', }, }]); @@ -228,7 +228,7 @@ test('chart labels are applied to all api objects in the chart', () => { bar: 'bbbbbb', foo: 'ffffffffff', }, - name: 'my-chart-obj1-01c0df67', + name: 'my-chart-obj1-c880bc50', }, }, { @@ -240,7 +240,7 @@ test('chart labels are applied to all api objects in the chart', () => { foo: 'override by object', zoo: 'zoo1', }, - name: 'my-chart-group-obj2-ba1eb578', + name: 'my-chart-group-obj2-c824cfcd', }, }, ]); @@ -319,7 +319,7 @@ describe('addJsonPatch()', () => { apiVersion: 'v1', kind: 'Obj', metadata: { - name: 'test-obj-822728f1', + name: 'test-obj-c8686f96', }, spec: { apiVersion: 'v1', diff --git a/packages/cdk8s/test/helm.test.ts b/packages/cdk8s/test/helm.test.ts index 9153469405..a08c1fee5d 100644 --- a/packages/cdk8s/test/helm.test.ts +++ b/packages/cdk8s/test/helm.test.ts @@ -16,7 +16,7 @@ test('basic usage', () => { }); // THEN - expect(helm.releaseName).toEqual('test-sample-00742e24'); + expect(helm.releaseName).toEqual('test-sample-c8e2763d'); expect(Testing.synth(chart)).toMatchSnapshot(); }); @@ -81,14 +81,14 @@ test('it is possible to interact with api objects in the chart', () => { chart: SAMPLE_CHART_PATH, }); - const service = helm.apiObjects.find(o => o.kind === 'ServiceAccount' && o.name === 'test-sample-00742e24-helm-sample'); + const service = helm.apiObjects.find(o => o.kind === 'ServiceAccount' && o.name === 'test-sample-c8e2763d-helm-sample'); service?.metadata.addAnnotation('my.annotation', 'hey-there'); // THEN expect(helm.apiObjects.map(o => `${o.kind}/${o.name}`).sort()).toEqual([ - 'Deployment/test-sample-00742e24-helm-sample', - 'Service/test-sample-00742e24-helm-sample', - 'ServiceAccount/test-sample-00742e24-helm-sample', + 'Deployment/test-sample-c8e2763d-helm-sample', + 'Service/test-sample-c8e2763d-helm-sample', + 'ServiceAccount/test-sample-c8e2763d-helm-sample', ]); expect(service?.toJson().metadata.annotations).toEqual({ @@ -123,7 +123,7 @@ test('helmFlags can be used to specify additional helm options', () => { 'template', '--description', 'my custom description', '--no-hooks', - 'test-sample-00742e24', + 'test-sample-c8e2763d', SAMPLE_CHART_PATH, ]; diff --git a/packages/cdk8s/test/names-legacy.test.ts b/packages/cdk8s/test/names-legacy.test.ts new file mode 100644 index 0000000000..15e86290d7 --- /dev/null +++ b/packages/cdk8s/test/names-legacy.test.ts @@ -0,0 +1,151 @@ +import { Names } from '../src/names'; +import { createTree } from './util'; + +const toDnsName = (path: string, maxLen?: number) => Names.toDnsLabel(createTree(path), { maxLen }); +const toLabelValue = (path: string, delimiter?: string, maxLen?: number) => Names.toLabelValue(createTree(path), { maxLen, delimiter }); + +beforeAll(() => process.env.CDK8S_LEGACY_HASH = '1'); +afterAll(() => delete process.env.CDK8S_LEGACY_HASH); + +describe('toDnsLabel', () => { + test('ignores default children', () => { + expect(toDnsName('hello/default/foo/world/default')).toEqual('hello-foo-world-5d193db9'); + expect(toDnsName('hello/resource/foo/world/resource')).toEqual('hello-foo-world-f5dd971f'); + expect(toDnsName('hello/resource/foo/world/default')).toEqual('hello-foo-world-2f1cee85'); + expect(toDnsName('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-857189b5'); + expect(toDnsName('hello/default/foo/world/resource')).toEqual('hello-foo-world-e89fdfae'); + expect(toDnsName('resource/default')).toEqual('40b6bcd9'); + }); + + test('normalize to dns_name', () => { + expect(toDnsName(' ')).toEqual('36a9e7f1'); + expect(toDnsName('Hello')).toEqual('hello-185f8db3'); + expect(toDnsName('hey*')).toEqual('hey-96c05e6c'); + expect(toDnsName('not allowed')).toEqual('notallowed-a26075ed'); + }); + + test('maximum length for a single term', () => { + expect(toDnsName('1234567890abcdef', 15)).toEqual('123456-8e9916c5'); + expect(toDnsName('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69f4ba1'); + }); + + test('single term is not decorated with a hash', () => { + expect(toDnsName('foo')).toEqual('foo'); + expect(toDnsName('foo-bar-123-455')).toEqual('foo-bar-123-455'); + expect(toDnsName('z'.repeat(63))).toEqual('z'.repeat(63)); + }); + + test('multiple terms are separated by "." and a hash is appended', () => { + expect(toDnsName('hello-foo-world')).toEqual('hello-foo-world'); // this is actually a single term + expect(toDnsName('hello-hello-foo-world')).toEqual('hello-hello-foo-world'); // intentionally duplicated + expect(toDnsName('hello-foo/world')).toEqual('hello-foo-world-54700203'); // two terms + expect(toDnsName('hello-foo/foo')).toEqual('hello-foo-foo-e078a973'); // two terms, intentionally duplicated + expect(toDnsName('hello/foo/world')).toEqual('hello-foo-world-4f6e4fd8'); // three terms + }); + + test('invalid max length (minimum is 8 - for hash)', () => { + const expected = /minimum max length for object names is 8/; + expect(() => toDnsName('foo', 4)).toThrow(expected); + expect(() => toDnsName('foo', 7)).toThrow(expected); + + // these are ok + expect(toDnsName('foo', 8)).toEqual('foo'); + expect(toDnsName('foo', 9)).toEqual('foo'); + }); + + test('omit duplicate components in names', () => { + expect(toDnsName('hello/hello/foo/world')).toEqual('hello-foo-world-1d4999d0'); + expect(toDnsName('hello/hello/hello/foo/world')).toEqual('hello-foo-world-d3ebcda3'); + expect(toDnsName('hello/hello/hello/hello/hello')).toEqual('hello-456bb9d7'); + expect(toDnsName('hello/cool/cool/cool/cool')).toEqual('hello-cool-83150e81'); + expect(toDnsName('hello/world/world/world/cool')).toEqual('hello-world-cool-0148a798'); + }); + + test('trimming (prioritize last component)', () => { + expect(toDnsName('hello/world', 8)).toEqual('761e91eb'); + expect(toDnsName('hello/world/this/is/cool', 8)).toEqual('a7c39f00'); + expect(toDnsName('hello/world/this/is/cool', 12)).toEqual('coo-a7c39f00'); + expect(toDnsName('hello/hello/this/is/cool', 12)).toEqual('coo-8751188b'); + expect(toDnsName('hello/cool/cool/cool/cool', 15)).toEqual('h-cool-83150e81'); + expect(toDnsName('hello/world/this/is/cool', 14)).toEqual('cool-a7c39f00'); + expect(toDnsName('hello/world/this/is/cool', 15)).toEqual('i-cool-a7c39f00'); + expect(toDnsName('hello/world/this/is/cool', 25)).toEqual('wor-this-is-cool-a7c39f00'); + }); + + test('filter empty components', () => { + expect(toDnsName('hello/world---this-is-cool---')).toEqual('hello-world-this-is-cool-85209c22'); + expect(toDnsName('hello-world-this-is-cool')).toEqual('hello-world-this-is-cool'); + expect(toDnsName('hello/world-this/is-cool')).toEqual('hello-world-this-is-cool-9bdccb95'); + }); +}); + +describe('toLabel', () => { + test('ignores default children', () => { + expect(toLabelValue('hello/default/foo/world/default')).toEqual('hello-foo-world-5d193db9'); + expect(toLabelValue('hello/resource/foo/world/resource')).toEqual('hello-foo-world-f5dd971f'); + expect(toLabelValue('hello/resource/foo/world/default')).toEqual('hello-foo-world-2f1cee85'); + expect(toLabelValue('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-857189b5'); + expect(toLabelValue('hello/default/foo/world/resource')).toEqual('hello-foo-world-e89fdfae'); + expect(toLabelValue('resource/default')).toEqual('40b6bcd9'); + }); + + test('normalize to dns_name', () => { + expect(toLabelValue(' ')).toEqual('36a9e7f1'); + expect(toLabelValue('Hello')).toEqual('Hello'); // Upper case is allowed for a label + expect(toLabelValue('hey*')).toEqual('hey-96c05e6c'); + expect(toLabelValue('not allowed')).toEqual('notallowed-a26075ed'); + }); + + test('maximum length for a single term', () => { + expect(toLabelValue('1234567890abcdef', '-', 15)).toEqual('123456-8e9916c5'); + expect(toLabelValue('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69f4ba1'); + }); + + test('single term is not decorated with a hash', () => { + expect(toLabelValue('foo')).toEqual('foo'); + expect(toLabelValue('foo-bar-123-455')).toEqual('foo-bar-123-455'); + expect(toLabelValue('z'.repeat(63))).toEqual('z'.repeat(63)); + }); + + test('multiple terms are separated by "." and a hash is appended', () => { + expect(toLabelValue('hello-foo-world')).toEqual('hello-foo-world'); // this is actually a single term + expect(toLabelValue('hello-hello-foo-world')).toEqual('hello-hello-foo-world'); // intentionally duplicated + expect(toLabelValue('hello-foo/world')).toEqual('hello-foo-world-54700203'); // two terms + expect(toLabelValue('hello-foo/foo')).toEqual('hello-foo-foo-e078a973'); // two terms, intentionally duplicated + expect(toLabelValue('hello/foo/world')).toEqual('hello-foo-world-4f6e4fd8'); // three terms + }); + + test('invalid max length (minimum is 8 - for hash)', () => { + const expected = /minimum max length for label is 8/; + expect(() => toLabelValue('foo', '-', 4)).toThrow(expected); + expect(() => toLabelValue('foo', '-', 7)).toThrow(expected); + + // these are ok + expect(toLabelValue('foo', '-', 8)).toEqual('foo'); + expect(toLabelValue('foo', '-', 9)).toEqual('foo'); + }); + + test('omit duplicate components in names', () => { + expect(toLabelValue('hello/hello/foo/world')).toEqual('hello-foo-world-1d4999d0'); + expect(toLabelValue('hello/hello/hello/foo/world')).toEqual('hello-foo-world-d3ebcda3'); + expect(toLabelValue('hello/hello/hello/hello/hello')).toEqual('hello-456bb9d7'); + expect(toLabelValue('hello/cool/cool/cool/cool')).toEqual('hello-cool-83150e81'); + expect(toLabelValue('hello/world/world/world/cool')).toEqual('hello-world-cool-0148a798'); + }); + + test('trimming (prioritize last component)', () => { + expect(toLabelValue('hello/world', '-', 8)).toEqual('761e91eb'); + expect(toLabelValue('hello/world/this/is/cool', '-', 8)).toEqual('a7c39f00'); + expect(toLabelValue('hello/world/this/is/cool', '-', 12)).toEqual('coo-a7c39f00'); + expect(toLabelValue('hello/hello/this/is/cool', '-', 12)).toEqual('coo-8751188b'); + expect(toLabelValue('hello/cool/cool/cool/cool', '-', 15)).toEqual('h-cool-83150e81'); + expect(toLabelValue('hello/world/this/is/cool', '-', 14)).toEqual('cool-a7c39f00'); + expect(toLabelValue('hello/world/this/is/cool', '-', 15)).toEqual('i-cool-a7c39f00'); + expect(toLabelValue('hello/world/this/is/cool', '-', 25)).toEqual('wor-this-is-cool-a7c39f00'); + }); + + test('filter empty components', () => { + expect(toLabelValue('hello---this/is/cool/-')).toEqual('hello-this-is-cool-a30e4c1e'); + expect(toLabelValue('hello---this/is---/cool/-')).toEqual('hello-this-is-cool-a9b9d489'); + }); +}); \ No newline at end of file diff --git a/packages/cdk8s/test/names.test.ts b/packages/cdk8s/test/names.test.ts index 915e05ef56..ba45fc9530 100644 --- a/packages/cdk8s/test/names.test.ts +++ b/packages/cdk8s/test/names.test.ts @@ -1,27 +1,28 @@ -import { Names } from '../src/names'; +import { NameOptions, Names } from '../src/names'; +import { createTree } from './util'; + +const toDnsName = (path: string, options: NameOptions = { }) => Names.toDnsLabel(createTree(path), options); +const toLabelValue = (path: string, options: NameOptions = { }) => Names.toLabelValue(createTree(path), options); describe('toDnsLabel', () => { - const toDnsName = Names.toDnsLabel; test('ignores default children', () => { - expect(toDnsName('hello/default/foo/world/default')).toEqual('hello-foo-world-5d193db9'); - expect(toDnsName('hello/resource/foo/world/resource')).toEqual('hello-foo-world-f5dd971f'); - expect(toDnsName('hello/resource/foo/world/default')).toEqual('hello-foo-world-2f1cee85'); - expect(toDnsName('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-857189b5'); - expect(toDnsName('hello/default/foo/world/resource')).toEqual('hello-foo-world-e89fdfae'); - expect(toDnsName('resource/default')).toEqual('40b6bcd9'); + expect(toDnsName('hello/default/foo/world/default')).toEqual('hello-foo-world-c8ceb89a'); + expect(toDnsName('hello/resource/foo/world/resource')).toEqual('hello-foo-world-c8c051a2'); + expect(toDnsName('hello/resource/foo/world/default')).toEqual('hello-foo-world-c8285558'); + expect(toDnsName('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-c8455d08'); + expect(toDnsName('hello/default/foo/world/resource')).toEqual('hello-foo-world-c83a0f50'); + expect(toDnsName('resource/default')).toEqual('c818ce2d'); }); test('normalize to dns_name', () => { - expect(toDnsName(' ')).toEqual('36a9e7f1'); - expect(toDnsName('')).toEqual('e3b0c442'); - expect(toDnsName('Hello')).toEqual('hello-185f8db3'); - expect(toDnsName('hey*')).toEqual('hey-96c05e6c'); - expect(toDnsName('not allowed')).toEqual('notallowed-a26075ed'); + expect(toDnsName('Hello')).toEqual('hello-c8a347e4'); + expect(toDnsName('hey*')).toEqual('hey-c808ed9e'); + expect(toDnsName('not allowed')).toEqual('notallowed-c82fed05'); }); test('maximum length for a single term', () => { - expect(toDnsName('1234567890abcdef', 15)).toEqual('123456-8e9916c5'); - expect(toDnsName('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69f4ba1'); + expect(toDnsName('1234567890abcdef', { maxLen: 15 })).toEqual('123456-c85fab94'); + expect(toDnsName('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-c86953f2'); }); test('single term is not decorated with a hash', () => { @@ -33,70 +34,67 @@ describe('toDnsLabel', () => { test('multiple terms are separated by "." and a hash is appended', () => { expect(toDnsName('hello-foo-world')).toEqual('hello-foo-world'); // this is actually a single term expect(toDnsName('hello-hello-foo-world')).toEqual('hello-hello-foo-world'); // intentionally duplicated - expect(toDnsName('hello-foo/world')).toEqual('hello-foo-world-54700203'); // two terms - expect(toDnsName('hello-foo/foo')).toEqual('hello-foo-foo-e078a973'); // two terms, intentionally duplicated - expect(toDnsName('hello/foo/world')).toEqual('hello-foo-world-4f6e4fd8'); // three terms + expect(toDnsName('hello-foo/world')).toEqual('hello-foo-world-c83c4a8a'); // two terms + expect(toDnsName('hello-foo/foo')).toEqual('hello-foo-foo-c884a60a'); // two terms, intentionally duplicated + expect(toDnsName('hello/foo/world')).toEqual('hello-foo-world-c89b166b'); // three terms }); test('invalid max length (minimum is 8 - for hash)', () => { const expected = /minimum max length for object names is 8/; - expect(() => toDnsName('foo', 4)).toThrow(expected); - expect(() => toDnsName('foo', 7)).toThrow(expected); + expect(() => toDnsName('foo', { maxLen: 4 })).toThrow(expected); + expect(() => toDnsName('foo', { maxLen: 7 })).toThrow(expected); // these are ok - expect(toDnsName('foo', 8)).toEqual('foo'); - expect(toDnsName('foo', 9)).toEqual('foo'); + expect(toDnsName('foo', { maxLen: 8 })).toEqual('foo'); + expect(toDnsName('foo', { maxLen: 9 })).toEqual('foo'); }); test('omit duplicate components in names', () => { - expect(toDnsName('hello/hello/foo/world')).toEqual('hello-foo-world-1d4999d0'); - expect(toDnsName('hello/hello/hello/foo/world')).toEqual('hello-foo-world-d3ebcda3'); - expect(toDnsName('hello/hello/hello/hello/hello')).toEqual('hello-456bb9d7'); - expect(toDnsName('hello/cool/cool/cool/cool')).toEqual('hello-cool-83150e81'); - expect(toDnsName('hello/world/world/world/cool')).toEqual('hello-world-cool-0148a798'); + expect(toDnsName('hello/hello/foo/world')).toEqual('hello-foo-world-c8538d75'); + expect(toDnsName('hello/hello/hello/foo/world')).toEqual('hello-foo-world-c815bea4'); + expect(toDnsName('hello/hello/hello/hello/hello')).toEqual('hello-c830c284'); + expect(toDnsName('hello/cool/cool/cool/cool')).toEqual('hello-cool-c816948a'); + expect(toDnsName('hello/world/world/world/cool')).toEqual('hello-world-cool-c8e259cb'); }); test('trimming (prioritize last component)', () => { - expect(toDnsName('hello/world', 8)).toEqual('761e91eb'); - expect(toDnsName('hello/world/this/is/cool', 8)).toEqual('a7c39f00'); - expect(toDnsName('hello/world/this/is/cool', 12)).toEqual('coo-a7c39f00'); - expect(toDnsName('hello/hello/this/is/cool', 12)).toEqual('coo-8751188b'); - expect(toDnsName('hello/cool/cool/cool/cool', 15)).toEqual('h-cool-83150e81'); - expect(toDnsName('hello/world/this/is/cool', 14)).toEqual('cool-a7c39f00'); - expect(toDnsName('hello/world/this/is/cool', 15)).toEqual('i-cool-a7c39f00'); - expect(toDnsName('hello/world/this/is/cool', 25)).toEqual('wor-this-is-cool-a7c39f00'); + expect(toDnsName('hello/world', { maxLen: 8 })).toEqual('c85bc96a'); + expect(toDnsName('hello/world/this/is/cool', { maxLen: 8 })).toEqual('c80ec725'); + expect(toDnsName('hello/world/this/is/cool', { maxLen: 12 })).toEqual('coo-c80ec725'); + expect(toDnsName('hello/hello/this/is/cool', { maxLen: 12 })).toEqual('coo-c812c430'); + expect(toDnsName('hello/cool/cool/cool/cool', { maxLen: 15 })).toEqual('h-cool-c816948a'); + expect(toDnsName('hello/world/this/is/cool', { maxLen: 14 })).toEqual('cool-c80ec725'); + expect(toDnsName('hello/world/this/is/cool', { maxLen: 15 })).toEqual('i-cool-c80ec725'); + expect(toDnsName('hello/world/this/is/cool', { maxLen: 25 })).toEqual('wor-this-is-cool-c80ec725'); }); test('filter empty components', () => { - expect(toDnsName('hello//world---this-is-cool---')).toEqual('hello-world-this-is-cool-52f679f4'); + expect(toDnsName('hello/world---this-is-cool---')).toEqual('hello-world-this-is-cool-c88665d5'); expect(toDnsName('hello-world-this-is-cool')).toEqual('hello-world-this-is-cool'); - expect(toDnsName('hello/world-this//is-cool')).toEqual('hello-world-this-is-cool-b6e3e997'); + expect(toDnsName('hello/world-this/is-cool')).toEqual('hello-world-this-is-cool-c81c7478'); }); }); describe('toLabel', () => { - const toLabelValue = Names.toLabelValue; test('ignores default children', () => { - expect(toLabelValue('hello/default/foo/world/default')).toEqual('hello-foo-world-5d193db9'); - expect(toLabelValue('hello/resource/foo/world/resource')).toEqual('hello-foo-world-f5dd971f'); - expect(toLabelValue('hello/resource/foo/world/default')).toEqual('hello-foo-world-2f1cee85'); - expect(toLabelValue('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-857189b5'); - expect(toLabelValue('hello/default/foo/world/resource')).toEqual('hello-foo-world-e89fdfae'); - expect(toLabelValue('resource/default')).toEqual('40b6bcd9'); + expect(toLabelValue('hello/default/foo/world/default')).toEqual('hello-foo-world-c8ceb89a'); + expect(toLabelValue('hello/resource/foo/world/resource')).toEqual('hello-foo-world-c8c051a2'); + expect(toLabelValue('hello/resource/foo/world/default')).toEqual('hello-foo-world-c8285558'); + expect(toLabelValue('hello/Resource/foo/world/Default')).toEqual('hello-foo-world-c8455d08'); + expect(toLabelValue('hello/default/foo/world/resource')).toEqual('hello-foo-world-c83a0f50'); + expect(toLabelValue('resource/default')).toEqual('c818ce2d'); }); test('normalize to dns_name', () => { - expect(toLabelValue(' ')).toEqual('36a9e7f1'); - expect(toLabelValue('')).toEqual(''); // Empty label is allowed for a label value expect(toLabelValue('Hello')).toEqual('Hello'); // Upper case is allowed for a label - expect(toLabelValue('hey*')).toEqual('hey-96c05e6c'); - expect(toLabelValue('not allowed')).toEqual('notallowed-a26075ed'); + expect(toLabelValue('hey*')).toEqual('hey-c808ed9e'); + expect(toLabelValue('not allowed')).toEqual('notallowed-c82fed05'); }); test('maximum length for a single term', () => { - expect(toLabelValue('1234567890abcdef', '-', 15)).toEqual('123456-8e9916c5'); - expect(toLabelValue('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69f4ba1'); + expect(toLabelValue('1234567890abcdef', { maxLen: 15, delimiter: '-' })).toEqual('123456-c85fab94'); + expect(toLabelValue('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-c86953f2'); }); test('single term is not decorated with a hash', () => { @@ -108,42 +106,42 @@ describe('toLabel', () => { test('multiple terms are separated by "." and a hash is appended', () => { expect(toLabelValue('hello-foo-world')).toEqual('hello-foo-world'); // this is actually a single term expect(toLabelValue('hello-hello-foo-world')).toEqual('hello-hello-foo-world'); // intentionally duplicated - expect(toLabelValue('hello-foo/world')).toEqual('hello-foo-world-54700203'); // two terms - expect(toLabelValue('hello-foo/foo')).toEqual('hello-foo-foo-e078a973'); // two terms, intentionally duplicated - expect(toLabelValue('hello/foo/world')).toEqual('hello-foo-world-4f6e4fd8'); // three terms + expect(toLabelValue('hello-foo/world')).toEqual('hello-foo-world-c83c4a8a'); // two terms + expect(toLabelValue('hello-foo/foo')).toEqual('hello-foo-foo-c884a60a'); // two terms, intentionally duplicated + expect(toLabelValue('hello/foo/world')).toEqual('hello-foo-world-c89b166b'); // three terms }); test('invalid max length (minimum is 8 - for hash)', () => { const expected = /minimum max length for label is 8/; - expect(() => toLabelValue('foo', '-', 4)).toThrow(expected); - expect(() => toLabelValue('foo', '-', 7)).toThrow(expected); + expect(() => toLabelValue('foo', { maxLen: 4 })).toThrow(expected); + expect(() => toLabelValue('foo', { maxLen: 7 })).toThrow(expected); // these are ok - expect(toLabelValue('foo', '-', 8)).toEqual('foo'); - expect(toLabelValue('foo', '-', 9)).toEqual('foo'); + expect(toLabelValue('foo', { maxLen: 8 })).toEqual('foo'); + expect(toLabelValue('foo', { maxLen: 9 })).toEqual('foo'); }); test('omit duplicate components in names', () => { - expect(toLabelValue('hello/hello/foo/world')).toEqual('hello-foo-world-1d4999d0'); - expect(toLabelValue('hello/hello/hello/foo/world')).toEqual('hello-foo-world-d3ebcda3'); - expect(toLabelValue('hello/hello/hello/hello/hello')).toEqual('hello-456bb9d7'); - expect(toLabelValue('hello/cool/cool/cool/cool')).toEqual('hello-cool-83150e81'); - expect(toLabelValue('hello/world/world/world/cool')).toEqual('hello-world-cool-0148a798'); + expect(toLabelValue('hello/hello/foo/world')).toEqual('hello-foo-world-c8538d75'); + expect(toLabelValue('hello/hello/hello/foo/world')).toEqual('hello-foo-world-c815bea4'); + expect(toLabelValue('hello/hello/hello/hello/hello')).toEqual('hello-c830c284'); + expect(toLabelValue('hello/cool/cool/cool/cool')).toEqual('hello-cool-c816948a'); + expect(toLabelValue('hello/world/world/world/cool')).toEqual('hello-world-cool-c8e259cb'); }); test('trimming (prioritize last component)', () => { - expect(toLabelValue('hello/world', '-', 8)).toEqual('761e91eb'); - expect(toLabelValue('hello/world/this/is/cool', '-', 8)).toEqual('a7c39f00'); - expect(toLabelValue('hello/world/this/is/cool', '-', 12)).toEqual('coo-a7c39f00'); - expect(toLabelValue('hello/hello/this/is/cool', '-', 12)).toEqual('coo-8751188b'); - expect(toLabelValue('hello/cool/cool/cool/cool', '-', 15)).toEqual('h-cool-83150e81'); - expect(toLabelValue('hello/world/this/is/cool', '-', 14)).toEqual('cool-a7c39f00'); - expect(toLabelValue('hello/world/this/is/cool', '-', 15)).toEqual('i-cool-a7c39f00'); - expect(toLabelValue('hello/world/this/is/cool', '-', 25)).toEqual('wor-this-is-cool-a7c39f00'); + expect(toLabelValue('hello/world', { maxLen: 8 })).toEqual('c85bc96a'); + expect(toLabelValue('hello/world/this/is/cool', { maxLen: 8 })).toEqual('c80ec725'); + expect(toLabelValue('hello/world/this/is/cool', { maxLen: 12 })).toEqual('coo-c80ec725'); + expect(toLabelValue('hello/hello/this/is/cool', { maxLen: 12 })).toEqual('coo-c812c430'); + expect(toLabelValue('hello/cool/cool/cool/cool', { maxLen: 15 })).toEqual('h-cool-c816948a'); + expect(toLabelValue('hello/world/this/is/cool', { maxLen: 14 })).toEqual('cool-c80ec725'); + expect(toLabelValue('hello/world/this/is/cool', { maxLen: 15 })).toEqual('i-cool-c80ec725'); + expect(toLabelValue('hello/world/this/is/cool', { maxLen: 25 })).toEqual('wor-this-is-cool-c80ec725'); }); test('filter empty components', () => { - expect(toLabelValue('hello---this/is//cool//-')).toEqual('hello-this-is-cool-dfb4c573'); - expect(toLabelValue('hello---this/is---//cool////-')).toEqual('hello-this-is-cool-84d02267'); + expect(toLabelValue('hello---this/is/cool/-')).toEqual('hello-this-is-cool-c83b900b'); + expect(toLabelValue('hello---this/is---/cool/-')).toEqual('hello-this-is-cool-c82d69dd'); }); }); \ No newline at end of file diff --git a/packages/cdk8s/test/util.ts b/packages/cdk8s/test/util.ts new file mode 100644 index 0000000000..a3a9e490f9 --- /dev/null +++ b/packages/cdk8s/test/util.ts @@ -0,0 +1,13 @@ +import { Construct } from 'constructs'; + +export function createTree(path: string) { + const queue = path.split('/'); + let curr = new Construct(undefined as any, undefined as any); + + while (queue.length) { + const id = queue.shift() as string; + curr = new Construct(curr, id!); + } + + return curr; +} diff --git a/packages/projen-common.js b/packages/projen-common.js index dce5d1a1ed..b8adda5ca4 100644 --- a/packages/projen-common.js +++ b/packages/projen-common.js @@ -1,6 +1,6 @@ exports.versions = { - constructs: '3.0.4', - jsii: '1.9.0', + constructs: '3.2.34', + jsii: '1.14.1', }; exports.options = { diff --git a/yarn.lock b/yarn.lock index 59f056939b..25e87ecb93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3047,6 +3047,11 @@ constructs@3.0.4: resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.0.4.tgz#eb1ed5b80f6600b8d50de83971357ae0fe8e29a2" integrity sha512-CDvg7gMjphE3DFX4pzkF6j73NREbR8npPFW8Mx/CLRnMR035+Y1o1HrXIsNSss/dq3ZUnNTU9jKyd3fL9EOlfw== +constructs@3.2.34: + version "3.2.34" + resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.2.34.tgz#e877e0c903b1be74429427179c3df1e0c4c964f0" + integrity sha512-BEc18syAsY2D3sYFXpa0HBuYj2yN0yhD24xHi5IYb1/5Xisbjm9ZKCsd3W9ko9Sy9BsB6w2lCA5dOqty14LNHg== + contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" @@ -3460,7 +3465,7 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-equal@^2.0.3: +deep-equal@^2.0.3, deep-equal@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.4.tgz#6b0b407a074666033169df3acaf128e1c6f3eab6" integrity sha512-BUfaXrVoCfgkOQY/b09QdO9L3XNoF2XH0A3aY9IQwQL/ZjLOe8FQgCNVl1wiolhsFo8kFdO9zdPViCPbmaJA5w== @@ -6595,17 +6600,17 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.9.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.13.0.tgz#91f3276dda151fdae2c9a0262666ecdcf44576ea" - integrity sha512-8yc4QjmXzoMjAPVMUD+BJNvBKhqM4sEXR3XUGz3/gCa8tbqvpEGsBjXHEnWlU5BHJU5uUpt0HFF+yEVpDg9YuQ== +jsii-diff@^1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.14.1.tgz#6ee1b6de68675a8cf8ad45b98474cbc7148c1aca" + integrity sha512-4lUf7++fply4tEW+HmhExjOCTz2zCihOdcn+bYvssG+2ztuFh+uyhUtcBaxXM49Mz8+RP3ymu3ArLr9BVmSfrg== dependencies: - "@jsii/spec" "^1.13.0" + "@jsii/spec" "^1.14.1" fs-extra "^9.0.1" - jsii-reflect "^1.13.0" + jsii-reflect "^1.14.1" log4js "^6.3.0" typescript "~3.9.7" - yargs "^16.0.3" + yargs "^16.1.0" jsii-docgen@^1.3.2: version "1.4.64" @@ -6617,7 +6622,7 @@ jsii-docgen@^1.3.2: jsii-reflect "^1.9.0" yargs "^15.4.1" -jsii-pacmak@^1.12.0, jsii-pacmak@^1.9.0: +jsii-pacmak@^1.12.0: version "1.13.0" resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.13.0.tgz#28cc1cd4013142aa6169a4e04fd14abe8a42c559" integrity sha512-I297/yAdNnEyEIE2X+Vv2KVdxBOT7KCF/9ZPpPyReAsPfh0RULbUyUH+qhfS9DnblmvjMF8fOjoJHGC5DcZlFQ== @@ -6715,7 +6720,7 @@ jsii-srcmak@^0.1.36: ncp "^2.0.0" yargs "^15.4.1" -jsii@^1.12.0, jsii@^1.9.0: +jsii@^1.12.0: version "1.13.0" resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.13.0.tgz#8a2ac2f60cd666d0ed76dc39204321caa7c9c775" integrity sha512-SA4YEegodByqI04BrRbR29QE+MGHGVQ5wG7byLDjVle0zRfRaJYc2nH13Jy4nhkC1aqBkRwHI9atKUrNDiNa0w== @@ -6733,6 +6738,24 @@ jsii@^1.12.0, jsii@^1.9.0: typescript "~3.9.7" yargs "^16.0.3" +jsii@^1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.14.1.tgz#4b478b5f682ae140fbfdd49c171b0cff7f7e01bd" + integrity sha512-uDVBl8bvSnraJpKYyY22dOoERpQv/sEAHEj3L5b00qkBi6FsFr2KWfQOdUg9fMWdYrmMVuXWOWXJ186Fn7XF+A== + dependencies: + "@jsii/spec" "^1.14.1" + case "^1.6.3" + colors "^1.4.0" + deep-equal "^2.0.4" + fs-extra "^9.0.1" + log4js "^6.3.0" + semver "^7.3.2" + semver-intersect "^1.4.0" + sort-json "^2.0.0" + spdx-license-list "^6.3.0" + typescript "~3.9.7" + yargs "^16.1.0" + json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"