@gooddata/code-cli 0.50.0-alpha.4 → 0.50.0-alpha.6

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.
package/dist/index.js CHANGED
@@ -37370,7 +37370,7 @@ function isPromise(value) {
37370
37370
  //#endregion
37371
37371
  //#region package.json
37372
37372
  var name$1 = "@gooddata/code-cli";
37373
- var version$1 = "0.50.0-alpha.4";
37373
+ var version$1 = "0.50.0-alpha.6";
37374
37374
  //#endregion
37375
37375
  //#region ../../../common/temp/aac/node_modules/.pnpm/vscode-languageserver@8.1.0/node_modules/vscode-languageserver/lib/common/utils/is.js
37376
37376
  var require_is$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -80599,6 +80599,7 @@ var require_follow_redirects$1 = /* @__PURE__ */ __commonJSMin(((exports, module
80599
80599
  */
80600
80600
  const tigerIdTypeToObjectType = {
80601
80601
  attribute: "attribute",
80602
+ computedAttribute: "computedAttribute",
80602
80603
  metric: "measure",
80603
80604
  label: "displayForm",
80604
80605
  dataset: "dataSet",
@@ -87717,8 +87718,26 @@ var ErrorCodes;
87717
87718
  ErrorCodes[ErrorCodes["ParameterValueUncovered"] = 14] = "ParameterValueUncovered";
87718
87719
  })(ErrorCodes || (ErrorCodes = {}));
87719
87720
  //#endregion
87720
- //#region ../../../common/temp/aac/node_modules/.pnpm/gdc-maql-language-server@file+..+..+..+libs+gdc-maql-language-server/node_modules/gdc-maql-language-server/esm/findObjects.js
87721
+ //#region ../../../common/temp/aac/node_modules/.pnpm/gdc-maql-language-server@file+..+..+..+libs+gdc-maql-language-server/node_modules/gdc-maql-language-server/esm/maqlObjectTypes.js
87721
87722
  var import_tree = require_tree();
87723
+ /**
87724
+ * MAQL spells the computed-attribute object type with an underscore (`{computed_attribute/id}`),
87725
+ * while the Tiger entity type it maps onto is camelCase (`computedAttribute`). Every other MAQL
87726
+ * object type is spelled the same on both sides, so this is the only bridge the two need.
87727
+ */
87728
+ const MAQL_OBJECT_TYPE_TO_TIGER_TYPE = { computed_attribute: "computedAttribute" };
87729
+ /**
87730
+ * Translates an object type as written in MAQL into the Tiger entity type it denotes. Types that
87731
+ * are spelled identically on both sides are returned unchanged, so this is safe to apply to any
87732
+ * `{type/id}` token before looking the type up.
87733
+ *
87734
+ * Keep the MAQL spelling for anything user-facing (diagnostics quote what the author wrote).
87735
+ */
87736
+ function normalizeMaqlObjectType(maqlObjectType) {
87737
+ return MAQL_OBJECT_TYPE_TO_TIGER_TYPE[maqlObjectType] ?? maqlObjectType;
87738
+ }
87739
+ //#endregion
87740
+ //#region ../../../common/temp/aac/node_modules/.pnpm/gdc-maql-language-server@file+..+..+..+libs+gdc-maql-language-server/node_modules/gdc-maql-language-server/esm/findObjects.js
87722
87741
  const { AttributeTypeContext: AttributeTypeContext$1, MaqlParser: MaqlParser$4, NumericTypeContext: NumericTypeContext$1 } = import_dist$7.default;
87723
87742
  function findAllObjects(metric) {
87724
87743
  const finder = new ObjectFinder();
@@ -87738,12 +87757,13 @@ var ObjectFinder = class {
87738
87757
  const rbrace = ctx.tryGetToken(MaqlParser$4.RBRACE, 0);
87739
87758
  if (lbrace === void 0 || lbrace.symbol.tokenIndex === -1 || sep === void 0 || sep.symbol.tokenIndex === -1 || id === void 0 || id.symbol.tokenIndex === -1 || rbrace === void 0 || rbrace.symbol.tokenIndex === -1 || type === void 0) return;
87740
87759
  const range = antlrContextRange(ctx.start, ctx.stop);
87760
+ const tigerType = normalizeMaqlObjectType(type);
87741
87761
  this.objects.push({
87742
- tigerType: isTigerType(type) ? type : void 0,
87762
+ tigerType: isTigerType(tigerType) ? tigerType : void 0,
87743
87763
  actualType: type,
87744
87764
  id: ctx.ID().text,
87745
87765
  ref: {
87746
- type: tigerIdTypeToObjectType[type],
87766
+ type: tigerIdTypeToObjectType[tigerType],
87747
87767
  identifier: ctx.ID().text
87748
87768
  },
87749
87769
  range
@@ -89294,10 +89314,11 @@ var LdmObjects = class LdmObjects {
89294
89314
  labels;
89295
89315
  facts;
89296
89316
  metrics;
89317
+ computedAttributes;
89297
89318
  parameters;
89298
89319
  datasets;
89299
89320
  size;
89300
- constructor(attributes, facts, metrics, parameters, dates, datasets) {
89321
+ constructor(attributes, facts, metrics, parameters, dates, datasets, computedAttributes = []) {
89301
89322
  const processedAttributes = this.processAttributes(attributes);
89302
89323
  const processedDates = this.processDates(dates);
89303
89324
  const regularAttributes = processedAttributes.flatMap((item) => item.attributes);
@@ -89316,15 +89337,17 @@ var LdmObjects = class LdmObjects {
89316
89337
  };
89317
89338
  this.facts = facts.map((fact) => LdmObjects.toTigerMetadataObject(fact.fact));
89318
89339
  this.metrics = metrics.map((metric) => LdmObjects.toTigerMetadataObject(metric.measure));
89340
+ this.computedAttributes = computedAttributes.map((computedAttribute) => LdmObjects.toTigerMetadataObject(computedAttribute));
89319
89341
  this.parameters = parameters.map((parameter) => LdmObjects.toTigerMetadataObject(parameter));
89320
89342
  this.datasets = datasets.map((dataset) => LdmObjects.toTigerDataset(dataset));
89321
- this.size = this.attributes.all.length + this.labels.all.length + this.facts.length + this.metrics.length + this.parameters.length;
89343
+ this.size = this.attributes.all.length + this.labels.all.length + this.facts.length + this.metrics.length + this.computedAttributes.length + this.parameters.length;
89322
89344
  }
89323
89345
  get(type, typeModifier = "all") {
89324
89346
  switch (type) {
89325
89347
  case "attribute": return this.attributes[typeModifier];
89326
89348
  case "fact": return this.facts;
89327
89349
  case "metric": return this.metrics;
89350
+ case "computedAttribute": return this.computedAttributes;
89328
89351
  case "parameter": return this.parameters;
89329
89352
  case "dataset": return this.datasets;
89330
89353
  case "label": return this.labels[typeModifier];
@@ -102867,6 +102890,7 @@ var SpecificCoreErrorCode;
102867
102890
  SpecificCoreErrorCode["UniquenessDatasetsId"] = "core.uniqueness.datasets.id";
102868
102891
  SpecificCoreErrorCode["UniquenessMetricsId"] = "core.uniqueness.metrics.id";
102869
102892
  SpecificCoreErrorCode["UniquenessParametersId"] = "core.uniqueness.parameters.id";
102893
+ SpecificCoreErrorCode["UniquenessComputedAttributesId"] = "core.uniqueness.computedAttributes.id";
102870
102894
  SpecificCoreErrorCode["UniquenessVisualisationsId"] = "core.uniqueness.visualisations.id";
102871
102895
  SpecificCoreErrorCode["UniquenessDashboardsId"] = "core.uniqueness.dashboards.id";
102872
102896
  SpecificCoreErrorCode["UniquenessPluginId"] = "core.uniqueness.plugins.id";
@@ -102913,6 +102937,7 @@ var CoreErrorCode;
102913
102937
  CoreErrorCode["MultipleCommonDateFilters"] = "core.multipleCommonDateFilters";
102914
102938
  CoreErrorCode["DuplicateFilterLocalIdentifier"] = "core.duplicateFilterLocalIdentifier";
102915
102939
  CoreErrorCode["DuplicateTabIdentifier"] = "core.duplicateTabIdentifier";
102940
+ CoreErrorCode["InvalidIanaTimezoneId"] = "core.invalidIanaTimezoneId";
102916
102941
  CoreErrorCode["MissingDataSourceId"] = "core.missingDataSourceId";
102917
102942
  CoreErrorCode["NonExistingRemoteReference"] = "core.nonExistingRemoteReference";
102918
102943
  CoreErrorCode["NonExistingRemoteReferences"] = "core.nonExistingRemoteReferences";
@@ -103006,11 +103031,13 @@ const CoreErrorMessages$1 = {
103006
103031
  [CoreErrorCode.MultipleCommonDateFilters]: `Multiple usage of common date filters in dashboard. Define exactly one date filter that has no date dataset defined.`,
103007
103032
  [CoreErrorCode.DuplicateFilterLocalIdentifier]: `Duplicate filter local identifier "{0}". Each filter must have a unique local identifier across a dashboard tab, including filters in groups.`,
103008
103033
  [CoreErrorCode.DuplicateTabIdentifier]: `Duplicate tab identifier "{0}". Each tab must have a unique identifier within the dashboard.`,
103034
+ [CoreErrorCode.InvalidIanaTimezoneId]: `"{0}" is not a valid IANA timezone ID. Use a real timezone such as Europe/Prague or $browserDetected.`,
103009
103035
  [CoreErrorCode.MissingDataSourceId]: `Missing data source. Data source must be specified in profile or directly on dataset. Use "data_source" property in profile or "data_source" property in current dataset definition.`,
103010
103036
  [CoreErrorCode.SqlIsNotRefreshedFromServer]: `SQL statement not loaded from server and need to be refreshed. Use "Run" button over the SQL statement to force retrieve new definition.`,
103011
103037
  [SpecificCoreErrorCode.UniquenessDatasetsId]: `There are more datasets with id "{0}". Use unique names for datasets.`,
103012
103038
  [SpecificCoreErrorCode.UniquenessMetricsId]: `There are more metrics with id "{0}". Use unique names for metrics.`,
103013
103039
  [SpecificCoreErrorCode.UniquenessParametersId]: `There are more parameters with id "{0}". Use unique names for parameters.`,
103040
+ [SpecificCoreErrorCode.UniquenessComputedAttributesId]: `There are more computed attributes with id "{0}". Use unique names for computed attributes.`,
103014
103041
  [SpecificCoreErrorCode.UniquenessVisualisationsId]: `There are more visualisations with id "{0}". Use unique names for visualisations.`,
103015
103042
  [SpecificCoreErrorCode.UniquenessDashboardsId]: `There are more dashboards with id "{0}". Use unique names for dashboards.`,
103016
103043
  [SpecificCoreErrorCode.UniquenessPluginId]: `There are more plugins with id "{0}". Use unique names for plugins.`,
@@ -103084,10 +103111,12 @@ const CoreErrorTypes$1 = {
103084
103111
  [CoreErrorCode.MultipleCommonDateFilters]: "MultipleCommonDateFilters",
103085
103112
  [CoreErrorCode.DuplicateFilterLocalIdentifier]: "DuplicateFilterLocalIdentifier",
103086
103113
  [CoreErrorCode.DuplicateTabIdentifier]: "DuplicateTabIdentifier",
103114
+ [CoreErrorCode.InvalidIanaTimezoneId]: "InvalidIanaTimezoneId",
103087
103115
  [CoreErrorCode.MissingDataSourceId]: "MissingDataSourceId",
103088
103116
  [SpecificCoreErrorCode.UniquenessDatasetsId]: "UniquenessDatasetsId",
103089
103117
  [SpecificCoreErrorCode.UniquenessMetricsId]: "UniquenessMetricsId",
103090
103118
  [SpecificCoreErrorCode.UniquenessParametersId]: "UniquenessParametersId",
103119
+ [SpecificCoreErrorCode.UniquenessComputedAttributesId]: "UniquenessComputedAttributesId",
103091
103120
  [SpecificCoreErrorCode.UniquenessPluginId]: "UniquenessPluginId",
103092
103121
  [SpecificCoreErrorCode.UniquenessAttributeHierarchyId]: "UniquenessAttributeHierarchyId",
103093
103122
  [SpecificCoreErrorCode.UniquenessDashboardWidgetLocalId]: "UniquenessDashboardWidgetLocalId",
@@ -106497,8 +106526,16 @@ const SupportedReferenceTypes$1 = [
106497
106526
  "dataset",
106498
106527
  "attribute"
106499
106528
  ];
106500
- /** MAQL can additionally name a parameter; custom URLs and shorthand fields cannot. */
106501
- const SupportedMaqlReferenceTypes = [...SupportedReferenceTypes$1, "parameter"];
106529
+ /**
106530
+ * MAQL can additionally name a parameter and a computed attribute; custom URLs and shorthand fields
106531
+ * cannot. The computed attribute token precedes "attribute" in the alternation the patterns build
106532
+ * from this list, so the longer token wins.
106533
+ */
106534
+ const SupportedMaqlReferenceTypes = [
106535
+ "computed_attribute",
106536
+ ...SupportedReferenceTypes$1,
106537
+ "parameter"
106538
+ ];
106502
106539
  /** The id fragment of a `type/id` reference, shared by every pattern that matches one. */
106503
106540
  const REFERENCE_ID_PATTERN = "(?!\\.)[.A-Za-z0-9_-]{1,255}";
106504
106541
  function parseReferenceObject$1(obj, supported = SupportedReferenceTypes$1) {
@@ -106580,6 +106617,7 @@ const DatasetTypes$2 = ["dataset"];
106580
106617
  const DateDatasetTypes$2 = ["date"];
106581
106618
  const MetricTypes$1 = ["metric"];
106582
106619
  const ParameterTypes$1 = ["parameter"];
106620
+ const ComputedAttributeTypes$1 = ["computed_attribute"];
106583
106621
  const AttrTypes$1 = ["attribute"];
106584
106622
  const FactTypes$1 = ["fact"];
106585
106623
  const AggregatedFactTypes = ["aggregated_fact"];
@@ -106620,6 +106658,7 @@ const TypesAll = allReferenceTypes([
106620
106658
  "dataset",
106621
106659
  "metric",
106622
106660
  "parameter",
106661
+ "computed_attribute",
106623
106662
  "area_chart",
106624
106663
  "bubble_chart",
106625
106664
  "bar_chart",
@@ -106681,6 +106720,10 @@ function isParameter(obj) {
106681
106720
  if (typeof obj === "object" && obj && "id" in obj && "type" in obj) return ParameterTypes$1.includes(obj.type);
106682
106721
  return false;
106683
106722
  }
106723
+ function isComputedAttribute(obj) {
106724
+ if (typeof obj === "object" && obj && "id" in obj && "type" in obj) return ComputedAttributeTypes$1.includes(obj.type);
106725
+ return false;
106726
+ }
106684
106727
  function isManifest(obj) {
106685
106728
  return !!(typeof obj === "object" && obj && "profiles" in obj && "source_dir" in obj);
106686
106729
  }
@@ -134833,6 +134876,69 @@ function isAttributeHierarchyReference(obj) {
134833
134876
  return !isEmpty(obj) && obj.type === "attributeHierarchyReference";
134834
134877
  }
134835
134878
  //#endregion
134879
+ //#region ../../../sdk/libs/sdk-model/esm/dashboard/dashboard.js
134880
+ /**
134881
+ * Value of {@link IDashboardTimezoneConfig.timezoneId} representing that the effective timezone
134882
+ * should be detected from the viewer's browser at load time. It is not a valid IANA identifier,
134883
+ * so it cannot collide with a real timezone.
134884
+ *
134885
+ * This sentinel is only allowed in the dashboard content ({@link DashboardTimezoneId}). Values
134886
+ * sent to executions or exports must always be concrete IANA IDs — resolve the sentinel first
134887
+ * via {@link resolveTimezoneId}.
134888
+ *
134889
+ * @alpha
134890
+ */
134891
+ const BROWSER_DETECTED$1 = "$browserDetected";
134892
+ /**
134893
+ * Tests whether the provided timezone value is the {@link BROWSER_DETECTED} sentinel.
134894
+ *
134895
+ * @param timezoneId - timezone value to test
134896
+ * @alpha
134897
+ */
134898
+ function isBrowserDetectedTimezone$1(timezoneId) {
134899
+ return timezoneId === BROWSER_DETECTED$1;
134900
+ }
134901
+ /**
134902
+ * Signed offset-style identifiers (`±HH`, `±HHMM`, `±HH:MM`, optionally with seconds).
134903
+ * Some `Intl` implementations accept these as `timeZone` values, but they are not named
134904
+ * IANA timezone IDs. Named IDs such as `"Etc/GMT+1"` do not match this pattern.
134905
+ */
134906
+ const OFFSET_STYLE_TIMEZONE_ID$1 = /^[+-]\d{2}(?:\d{2}|:\d{2}(?::\d{2}(?:\.\d+)?)?)?$/;
134907
+ /**
134908
+ * Tests whether `timezoneId` is a valid IANA timezone identifier according to
134909
+ * the runtime ICU data (via `Intl.DateTimeFormat`). The {@link BROWSER_DETECTED}
134910
+ * sentinel is not a valid IANA ID — use {@link isValidDashboardTimezoneId} for
134911
+ * values stored on the dashboard.
134912
+ *
134913
+ * Identifiers are case-sensitive. `Intl` accepts timezones case-insensitively, so
134914
+ * a value that only differs in case from the canonical form (e.g. `"america/new_york"`)
134915
+ * is rejected. Aliases that resolve to a different identifier (e.g. `"Etc/UTC"` → `"UTC"`)
134916
+ * are still accepted as ICU-known IDs. Offset-style identifiers (e.g. `"+01"`, `"+0100"`,
134917
+ * `"+01:00"`) are rejected.
134918
+ *
134919
+ * @param timezoneId - timezone identifier to test
134920
+ * @alpha
134921
+ */
134922
+ function isValidIanaTimezoneId$1(timezoneId) {
134923
+ if (OFFSET_STYLE_TIMEZONE_ID$1.test(timezoneId)) return false;
134924
+ try {
134925
+ const canonical = new Intl.DateTimeFormat(void 0, { timeZone: timezoneId }).resolvedOptions().timeZone;
134926
+ return canonical === timezoneId || canonical.toLowerCase() !== timezoneId.toLowerCase();
134927
+ } catch {
134928
+ return false;
134929
+ }
134930
+ }
134931
+ /**
134932
+ * Tests whether a dashboard timezone value is allowed in dashboard content:
134933
+ * {@link BROWSER_DETECTED}, or a valid IANA timezone ID.
134934
+ *
134935
+ * @param timezoneId - timezone value from the dashboard content
134936
+ * @alpha
134937
+ */
134938
+ function isValidDashboardTimezoneId$1(timezoneId) {
134939
+ return isBrowserDetectedTimezone$1(timezoneId) || isValidIanaTimezoneId$1(timezoneId);
134940
+ }
134941
+ //#endregion
134836
134942
  //#region ../../../sdk/libs/sdk-code-convertors/src/utils/errors.ts
134837
134943
  /**
134838
134944
  * @public
@@ -134853,7 +134959,8 @@ const CoreErrorMessages = {
134853
134959
  ["core.duplicateFilterName"]: `Duplicate filter name "{0}". Each filter in a query must have a unique name, including the filters a date filter carries.`,
134854
134960
  ["core.duplicateLayerIdentifier"]: `Duplicate layer id "{0}". Each layer of a visualisation must have a unique id.`,
134855
134961
  ["core.duplicateTabIdentifier"]: `Duplicate tab identifier "{0}". Each tab must have a unique identifier within the dashboard.`,
134856
- ["core.tabsAndRootContentMutuallyExclusive"]: `Dashboard "{0}" defines both "tabs" and root-level "sections" or "filters". These are mutually exclusive — keep all content inside tabs or at the root, not both.`
134962
+ ["core.tabsAndRootContentMutuallyExclusive"]: `Dashboard "{0}" defines both "tabs" and root-level "sections" or "filters". These are mutually exclusive — keep all content inside tabs or at the root, not both.`,
134963
+ ["core.invalidIanaTimezoneId"]: `"{0}" is not a valid IANA timezone ID. Use a real timezone such as Europe/Prague or $browserDetected.`
134857
134964
  };
134858
134965
  /**
134859
134966
  * @public
@@ -134874,7 +134981,8 @@ const CoreErrorTypes = {
134874
134981
  ["core.duplicateFilterName"]: "DuplicateFilterName",
134875
134982
  ["core.duplicateLayerIdentifier"]: "DuplicateLayerIdentifier",
134876
134983
  ["core.duplicateTabIdentifier"]: "DuplicateTabIdentifier",
134877
- ["core.tabsAndRootContentMutuallyExclusive"]: "TabsAndRootContentMutuallyExclusive"
134984
+ ["core.tabsAndRootContentMutuallyExclusive"]: "TabsAndRootContentMutuallyExclusive",
134985
+ ["core.invalidIanaTimezoneId"]: "InvalidIanaTimezoneId"
134878
134986
  };
134879
134987
  /**
134880
134988
  * Update error context with new values
@@ -135331,6 +135439,29 @@ function yamlParameterDefinitionToDeclarative(definition) {
135331
135439
  };
135332
135440
  }
135333
135441
  //#endregion
135442
+ //#region ../../../sdk/libs/sdk-code-convertors/src/to/yamlComputedAttributeToDeclarative.ts
135443
+ /**
135444
+ * A computed attribute is textual for now: the backend does not transfer the value type from
135445
+ * metadata yet, so every computed attribute is interpreted as a STRING/TEXT one. The YAML shape
135446
+ * therefore does not expose dataType/valueType and the defaults are filled in here.
135447
+ */
135448
+ const DEFAULT_DATA_TYPE = "STRING";
135449
+ const DEFAULT_VALUE_TYPE = "TEXT";
135450
+ /** @public */
135451
+ function yamlComputedAttributeToDeclarative(input) {
135452
+ const output = {
135453
+ id: input.id,
135454
+ title: input.title ?? convertIdToTitle$1(input.id),
135455
+ description: input.description ?? "",
135456
+ tags: input.tags ?? [],
135457
+ content: { maql: input.maql },
135458
+ dataType: DEFAULT_DATA_TYPE,
135459
+ valueType: DEFAULT_VALUE_TYPE
135460
+ };
135461
+ if (input.locale !== void 0) output.locale = input.locale;
135462
+ return output;
135463
+ }
135464
+ //#endregion
135334
135465
  //#region ../../../sdk/libs/sdk-code-convertors/src/configs/utils.ts
135335
135466
  /** @public */
135336
135467
  function getValueOrDefault(value, defaultValue, type = "string", undefinedAsDefault = false) {
@@ -140239,6 +140370,8 @@ const MetricTypes = ["metric"];
140239
140370
  /** @internal */
140240
140371
  const ParameterTypes = ["parameter"];
140241
140372
  /** @internal */
140373
+ const ComputedAttributeTypes = ["computed_attribute"];
140374
+ /** @internal */
140242
140375
  const DashboardTypes = ["dashboard"];
140243
140376
  /** @internal */
140244
140377
  const PluginTypes = ["plugin"];
@@ -140276,6 +140409,7 @@ const AllTypes = [
140276
140409
  ...DateDatasetTypes,
140277
140410
  ...MetricTypes,
140278
140411
  ...ParameterTypes,
140412
+ ...ComputedAttributeTypes,
140279
140413
  ...DashboardTypes,
140280
140414
  ...PluginTypes,
140281
140415
  ...VisualisationsTypes,
@@ -140797,8 +140931,9 @@ function yamlPluginToDeclarative$1(input) {
140797
140931
  parameters: serialiseParameters(input.parameters ?? "")
140798
140932
  };
140799
140933
  }
140800
- function yamlTimezoneConfigToDeclarative(input) {
140934
+ function yamlTimezoneConfigToDeclarative(input, errorContext) {
140801
140935
  if (!input) return;
140936
+ if (input.timezone_id !== void 0 && !isValidDashboardTimezoneId$1(input.timezone_id)) throw newError("core.invalidIanaTimezoneId", [input.timezone_id], updateErrorContext(errorContext, { path: ["timezone_config", "timezone_id"] }));
140802
140937
  return {
140803
140938
  ...input.timezone_id ? { timezoneId: input.timezone_id } : {},
140804
140939
  ...input.show_timezone_info ? { showTimezoneInfo: input.show_timezone_info } : {},
@@ -141083,6 +141218,12 @@ const DATE_INSTANCE_COMMENT = [
141083
141218
  " Read more about date instances:",
141084
141219
  " https://www.gooddata.com/developers/cloud-native/doc/cloud/model-data/concepts/dataset/#date-datasets"
141085
141220
  ].join("\n");
141221
+ const COMPUTED_ATTRIBUTE_COMMENT = [
141222
+ " A computed attribute turns numbers into named groups, for example \"Small\", \"Medium\", \"Large\".",
141223
+ " Write the break points in MAQL - the first matching branch wins - and use it like any attribute.",
141224
+ " Read more about MAQL:",
141225
+ " https://www.gooddata.com/developers/cloud-native/doc/cloud/create-metrics/maql/"
141226
+ ].join("\n");
141086
141227
  const METRIC_COMMENT = [
141087
141228
  " A metric is a computational expression of numerical data (facts or other metrics).",
141088
141229
  " Use MAQL to create reusable multidimensional queries that combine multiple facts and attributes.",
@@ -141337,6 +141478,23 @@ function declarativeParameterDefinitionToYaml(definition) {
141337
141478
  };
141338
141479
  }
141339
141480
  //#endregion
141481
+ //#region ../../../sdk/libs/sdk-code-convertors/src/from/declarativeComputedAttributeToYaml.ts
141482
+ /** @public */
141483
+ function declarativeComputedAttributeToYaml(computedAttribute) {
141484
+ const doc = new import_dist.Document({
141485
+ type: "computed_attribute",
141486
+ id: computedAttribute.id
141487
+ });
141488
+ doc.commentBefore = COMPUTED_ATTRIBUTE_COMMENT;
141489
+ fillOptionalMetaFields(doc, computedAttribute);
141490
+ doc.add(entryWithSpace("maql", computedAttribute.content.maql ?? ""));
141491
+ if (computedAttribute.locale) doc.add(doc.createPair("locale", computedAttribute.locale));
141492
+ return {
141493
+ content: doc.toString({ lineWidth: 0 }),
141494
+ json: doc.toJSON()
141495
+ };
141496
+ }
141497
+ //#endregion
141340
141498
  //#region ../../../sdk/libs/sdk-code-convertors/src/from/filtersToYaml.ts
141341
141499
  function detectEmptyValuesFilterType(filter) {
141342
141500
  const attributeElements = filterAttributeElements(filter);
@@ -143708,6 +143866,9 @@ const ID_PATTERN = new RegExp(`(${SupportedMaqlReferenceTypes.join("|")})\\/(${R
143708
143866
  function resolveMetricReferences(item) {
143709
143867
  return resolveMaqlReferences(item.maql ?? "");
143710
143868
  }
143869
+ function resolveComputedAttributeReferences(item) {
143870
+ return resolveMaqlReferences(item.maql ?? "");
143871
+ }
143711
143872
  function resolveMaqlReferences(maql) {
143712
143873
  const reg = new RegExp(ID_PATTERN.source, ID_PATTERN.flags);
143713
143874
  const all = [];
@@ -143963,6 +144124,7 @@ function containsReference(item, ref) {
143963
144124
  ...isDashboard(item) ? [createReferenceObject(item.id, "dashboard")] : [],
143964
144125
  ...isPlugin(item) ? [createReferenceObject(item.id, "plugin")] : [],
143965
144126
  ...isMetric(item) ? [createReferenceObject(item.id, "metric")] : [],
144127
+ ...isComputedAttribute(item) ? [createReferenceObject(item.id, "computed_attribute")] : [],
143966
144128
  ...isParameter(item) ? [createReferenceObject(item.id, "parameter")] : [],
143967
144129
  ...isAttributeHierarchy(item) ? [createReferenceObject(item.id, "attribute_hierarchy")] : []
143968
144130
  ].some((item) => item.type === ref.type && item.identifier === ref.identifier);
@@ -143972,6 +144134,7 @@ function collectItemReferences(item) {
143972
144134
  case "dataset":
143973
144135
  case "date": return resolveDatasetReferences$1(item);
143974
144136
  case "metric": return resolveMetricReferences(item);
144137
+ case "computed_attribute": return resolveComputedAttributeReferences(item);
143975
144138
  case "dashboard": return resolveDashboardReferences(item);
143976
144139
  case "plugin":
143977
144140
  case "parameter": return [];
@@ -144253,20 +144416,22 @@ function convertDateTitle(item, gran) {
144253
144416
  //#endregion
144254
144417
  //#region ../code/esm/features/references/resolve/objects.js
144255
144418
  function resolveLdmObjects(files) {
144256
- const { metrics, parameters, datasets, dates } = files.reduce((prev, item) => {
144419
+ const { metrics, computedAttributes, parameters, datasets, dates } = files.reduce((prev, item) => {
144257
144420
  if (isDataset$1(item)) prev.datasets.push(buildDataset(item));
144258
144421
  if (isDateDataset$1(item)) prev.dates.push(buildDate(item));
144259
144422
  if (isMetric(item)) prev.metrics.push(buildMetric(item));
144423
+ if (isComputedAttribute(item)) prev.computedAttributes.push(buildComputedAttribute(item));
144260
144424
  if (isParameter(item)) prev.parameters.push(buildParameter(item));
144261
144425
  return prev;
144262
144426
  }, {
144263
144427
  metrics: [],
144428
+ computedAttributes: [],
144264
144429
  parameters: [],
144265
144430
  dates: [],
144266
144431
  datasets: []
144267
144432
  });
144268
144433
  const { attributes, facts } = extractFromDatasets(datasets);
144269
- return new LdmObjects(attributes, facts, metrics, parameters, dates, datasets);
144434
+ return new LdmObjects(attributes, facts, metrics, parameters, dates, datasets, computedAttributes);
144270
144435
  }
144271
144436
  function extractFromDatasets(datasets) {
144272
144437
  const attributes = [];
@@ -144391,6 +144556,24 @@ function buildMetric(item) {
144391
144556
  groups: []
144392
144557
  };
144393
144558
  }
144559
+ /**
144560
+ * A computed attribute has no real labels, so unlike a normal attribute it contributes only itself
144561
+ * to the catalog - MAQL references it directly as `{computed_attribute/id}`, never through a label.
144562
+ */
144563
+ function buildComputedAttribute(item) {
144564
+ return {
144565
+ type: "computedAttribute",
144566
+ ...buildUriRef("computedAttribute", item.id),
144567
+ id: item.id,
144568
+ description: item.description ?? "",
144569
+ title: item.title ?? convertIdToTitle(item.id),
144570
+ expression: item.maql,
144571
+ production: true,
144572
+ deprecated: false,
144573
+ unlisted: false,
144574
+ displayForms: []
144575
+ };
144576
+ }
144394
144577
  function buildParameter(item) {
144395
144578
  return {
144396
144579
  type: "parameter",
@@ -145780,6 +145963,15 @@ function resolveReferencesByObjectSource(references, source, opts) {
145780
145963
  remote: false
145781
145964
  };
145782
145965
  }
145966
+ case "computedAttribute.id": {
145967
+ const [available, diagnostics] = resolveReferencesIds(references, ["computed_attribute"]);
145968
+ return {
145969
+ available: withPrefix(isComputedAttribute(references.self) ? available.filter(filterBySelf(references.self?.id)) : available, "computed_attribute", opts.typePrefix),
145970
+ ambiguous: getAmbiguous(available),
145971
+ diagnostics,
145972
+ remote: false
145973
+ };
145974
+ }
145783
145975
  case "dataset.field": {
145784
145976
  const [available, diagnostics] = resolveFieldsIds(references, ["dataset"]);
145785
145977
  return {
@@ -146661,6 +146853,13 @@ const metadata_v1 = {
146661
146853
  },
146662
146854
  "then": { "$ref": "#/$global/gaac/metric" }
146663
146855
  },
146856
+ {
146857
+ "if": {
146858
+ "properties": { "type": { "const": "computed_attribute" } },
146859
+ "required": ["type"]
146860
+ },
146861
+ "then": { "$ref": "#/$global/gaac/computed_attribute" }
146862
+ },
146664
146863
  {
146665
146864
  "if": {
146666
146865
  "properties": { "type": { "const": "dashboard" } },
@@ -146730,6 +146929,7 @@ const metadata_v1 = {
146730
146929
  "snippets": [
146731
146930
  "dataset",
146732
146931
  "metric",
146932
+ "computed_attribute",
146733
146933
  "date",
146734
146934
  "dashboard",
146735
146935
  "plugin",
@@ -146768,6 +146968,7 @@ const metadata_v1 = {
146768
146968
  "dataset",
146769
146969
  "date",
146770
146970
  "metric",
146971
+ "computed_attribute",
146771
146972
  "dashboard",
146772
146973
  "plugin",
146773
146974
  "table",
@@ -147105,6 +147306,59 @@ const metadata_v1 = {
147105
147306
  "maql"
147106
147307
  ]
147107
147308
  },
147309
+ "computed_attribute": {
147310
+ "title": "ComputedAttribute",
147311
+ "type": "object",
147312
+ "additionalProperties": false,
147313
+ "properties": {
147314
+ "id": {
147315
+ "$ref": "#/$global/gaac/identifier",
147316
+ "description": "A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.",
147317
+ "$semantic": [{
147318
+ "type": "uniqueness",
147319
+ "source": "computedAttribute.id",
147320
+ "code": "core.uniqueness.computedAttributes.id"
147321
+ }, {
147322
+ "type": "definition",
147323
+ "source": "computedAttribute.id"
147324
+ }]
147325
+ },
147326
+ "type": {
147327
+ "type": "string",
147328
+ "enum": ["computed_attribute"]
147329
+ },
147330
+ "title": {
147331
+ "$ref": "#/$global/gaac/title",
147332
+ "description": "An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly."
147333
+ },
147334
+ "description": {
147335
+ "$ref": "#/$global/gaac/description",
147336
+ "description": "An optional description of the computed attribute."
147337
+ },
147338
+ "tags": {
147339
+ "$ref": "#/$global/gaac/tags",
147340
+ "description": "A list of strings - metadata tags of this computed attribute."
147341
+ },
147342
+ "maql": {
147343
+ "type": "string",
147344
+ "description": "Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.",
147345
+ "$semantic": { "type": "maql" }
147346
+ },
147347
+ "locale": {
147348
+ "type": "string",
147349
+ "description": "An optional locale whose collation order the computed values are sorted by."
147350
+ }
147351
+ },
147352
+ "$semantic": {
147353
+ "type": "snippet",
147354
+ "snippets": ["computed_attribute"]
147355
+ },
147356
+ "required": [
147357
+ "id",
147358
+ "type",
147359
+ "maql"
147360
+ ]
147361
+ },
147108
147362
  "dashboard": {
147109
147363
  "title": "Dashboard",
147110
147364
  "type": "object",
@@ -151946,6 +152200,59 @@ const metadata_v1 = {
151946
152200
  "mode": "property"
151947
152201
  }
151948
152202
  },
152203
+ "computed_attribute": {
152204
+ "title": "ComputedAttribute",
152205
+ "type": "object",
152206
+ "additionalProperties": false,
152207
+ "properties": {
152208
+ "id": {
152209
+ "$ref": "#/$global/gaac/identifier",
152210
+ "description": "A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.",
152211
+ "$semantic": [{
152212
+ "type": "uniqueness",
152213
+ "source": "computedAttribute.id",
152214
+ "code": "core.uniqueness.computedAttributes.id"
152215
+ }, {
152216
+ "type": "definition",
152217
+ "source": "computedAttribute.id"
152218
+ }]
152219
+ },
152220
+ "type": {
152221
+ "type": "string",
152222
+ "enum": ["computed_attribute"]
152223
+ },
152224
+ "title": {
152225
+ "$ref": "#/$global/gaac/title",
152226
+ "description": "An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly."
152227
+ },
152228
+ "description": {
152229
+ "$ref": "#/$global/gaac/description",
152230
+ "description": "An optional description of the computed attribute."
152231
+ },
152232
+ "tags": {
152233
+ "$ref": "#/$global/gaac/tags",
152234
+ "description": "A list of strings - metadata tags of this computed attribute."
152235
+ },
152236
+ "maql": {
152237
+ "type": "string",
152238
+ "description": "Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.",
152239
+ "$semantic": { "type": "maql" }
152240
+ },
152241
+ "locale": {
152242
+ "type": "string",
152243
+ "description": "An optional locale whose collation order the computed values are sorted by."
152244
+ }
152245
+ },
152246
+ "$semantic": {
152247
+ "type": "snippet",
152248
+ "snippets": ["computed_attribute"]
152249
+ },
152250
+ "required": [
152251
+ "id",
152252
+ "type",
152253
+ "maql"
152254
+ ]
152255
+ },
151949
152256
  "widthItem": {
151950
152257
  "title": "Width",
151951
152258
  "type": "object",
@@ -152330,7 +152637,8 @@ const metadata_v1 = {
152330
152637
  }, {
152331
152638
  "type": "string",
152332
152639
  "pattern": "^[A-Za-z][A-Za-z0-9_+.-]*(?:/[A-Za-z0-9_+.-]+)*$"
152333
- }]
152640
+ }],
152641
+ "$semantic": { "type": "iana_timezone" }
152334
152642
  },
152335
152643
  "widget": {
152336
152644
  "title": "Widget",
@@ -156647,6 +156955,69 @@ function movePosition$2(fullDocument, point, position) {
156647
156955
  };
156648
156956
  }
156649
156957
  //#endregion
156958
+ //#region ../../../sdk/libs/sdk-model/src/dashboard/dashboard.ts
156959
+ /**
156960
+ * Value of {@link IDashboardTimezoneConfig.timezoneId} representing that the effective timezone
156961
+ * should be detected from the viewer's browser at load time. It is not a valid IANA identifier,
156962
+ * so it cannot collide with a real timezone.
156963
+ *
156964
+ * This sentinel is only allowed in the dashboard content ({@link DashboardTimezoneId}). Values
156965
+ * sent to executions or exports must always be concrete IANA IDs — resolve the sentinel first
156966
+ * via {@link resolveTimezoneId}.
156967
+ *
156968
+ * @alpha
156969
+ */
156970
+ const BROWSER_DETECTED = "$browserDetected";
156971
+ /**
156972
+ * Tests whether the provided timezone value is the {@link BROWSER_DETECTED} sentinel.
156973
+ *
156974
+ * @param timezoneId - timezone value to test
156975
+ * @alpha
156976
+ */
156977
+ function isBrowserDetectedTimezone(timezoneId) {
156978
+ return timezoneId === BROWSER_DETECTED;
156979
+ }
156980
+ /**
156981
+ * Signed offset-style identifiers (`±HH`, `±HHMM`, `±HH:MM`, optionally with seconds).
156982
+ * Some `Intl` implementations accept these as `timeZone` values, but they are not named
156983
+ * IANA timezone IDs. Named IDs such as `"Etc/GMT+1"` do not match this pattern.
156984
+ */
156985
+ const OFFSET_STYLE_TIMEZONE_ID = /^[+-]\d{2}(?:\d{2}|:\d{2}(?::\d{2}(?:\.\d+)?)?)?$/;
156986
+ /**
156987
+ * Tests whether `timezoneId` is a valid IANA timezone identifier according to
156988
+ * the runtime ICU data (via `Intl.DateTimeFormat`). The {@link BROWSER_DETECTED}
156989
+ * sentinel is not a valid IANA ID — use {@link isValidDashboardTimezoneId} for
156990
+ * values stored on the dashboard.
156991
+ *
156992
+ * Identifiers are case-sensitive. `Intl` accepts timezones case-insensitively, so
156993
+ * a value that only differs in case from the canonical form (e.g. `"america/new_york"`)
156994
+ * is rejected. Aliases that resolve to a different identifier (e.g. `"Etc/UTC"` → `"UTC"`)
156995
+ * are still accepted as ICU-known IDs. Offset-style identifiers (e.g. `"+01"`, `"+0100"`,
156996
+ * `"+01:00"`) are rejected.
156997
+ *
156998
+ * @param timezoneId - timezone identifier to test
156999
+ * @alpha
157000
+ */
157001
+ function isValidIanaTimezoneId(timezoneId) {
157002
+ if (OFFSET_STYLE_TIMEZONE_ID.test(timezoneId)) return false;
157003
+ try {
157004
+ const canonical = new Intl.DateTimeFormat(void 0, { timeZone: timezoneId }).resolvedOptions().timeZone;
157005
+ return canonical === timezoneId || canonical.toLowerCase() !== timezoneId.toLowerCase();
157006
+ } catch {
157007
+ return false;
157008
+ }
157009
+ }
157010
+ /**
157011
+ * Tests whether a dashboard timezone value is allowed in dashboard content:
157012
+ * {@link BROWSER_DETECTED}, or a valid IANA timezone ID.
157013
+ *
157014
+ * @param timezoneId - timezone value from the dashboard content
157015
+ * @alpha
157016
+ */
157017
+ function isValidDashboardTimezoneId(timezoneId) {
157018
+ return isBrowserDetectedTimezone(timezoneId) || isValidIanaTimezoneId(timezoneId);
157019
+ }
157020
+ //#endregion
156650
157021
  //#region ../code/esm/store/textDocument/update.js
156651
157022
  var ContentChangeMode;
156652
157023
  (function(ContentChangeMode) {
@@ -156806,6 +157177,7 @@ async function validateYamlSemantic(state, resolvedReferences, textDocument, sch
156806
157177
  results.push(validateYamlSemanticForRequiredCommonDate(resolvedReferences, schemas, schema, root, node));
156807
157178
  results.push(validateYamlSemanticForUniqueFilterLocalIdentifiers(schemas, schema, node));
156808
157179
  results.push(validateYamlSemanticForUniqueTabIdentifiers(schemas, schema, node));
157180
+ results.push(validateYamlSemanticForIanaTimezone(schemas, schema, node));
156809
157181
  return mergeSchemaValidatorDiagnostics(diagnostics, ...results);
156810
157182
  }
156811
157183
  async function validateYamlSemanticForMaql(state, resolvedReferences, textDocument, schema, root, node) {
@@ -157159,6 +157531,16 @@ function validateYamlSemanticForUniqueTabIdentifiers(schemas, schema, node) {
157159
157531
  return currentDiagnostics;
157160
157532
  }));
157161
157533
  }
157534
+ function validateYamlSemanticForIanaTimezone(schemas, schema, node) {
157535
+ return mergeSchemaValidatorDiagnostics(...getSemanticItems(schema.$semantic).map((semantic) => {
157536
+ const currentDiagnostics = createSchemaValidatorDiagnostics([]);
157537
+ if (semantic.type === "iana_timezone" && node.position) {
157538
+ const value = getNodeValue(node);
157539
+ if (typeof value === "string" && value.length > 0 && !isValidDashboardTimezoneId(value)) currentDiagnostics.diagnostics.push(createDiagnostic$1(SchemaDiagnosticSeverity.Error, node.position, getSchemaArray(schemas, schema), CoreErrorCode.InvalidIanaTimezoneId, CoreErrorMessages$1[CoreErrorCode.InvalidIanaTimezoneId], [value]));
157540
+ }
157541
+ return currentDiagnostics;
157542
+ }));
157543
+ }
157162
157544
  function hasConnectedField(property, semantic) {
157163
157545
  if (semantic?.connectedField) {
157164
157546
  const nodeValue = getNodeValue(getPropertyValueNode(property));
@@ -158257,6 +158639,7 @@ function buildSnippet(definition, type) {
158257
158639
  case "date": return buildSnippetForDateDataset(definition);
158258
158640
  case "metric": return buildSnippetForMetric(definition);
158259
158641
  case "parameter": return buildSnippetForParameter(definition);
158642
+ case "computed_attribute": return buildSnippetForComputedAttribute(definition);
158260
158643
  case "attribute": return buildSnippetForAttribute(definition);
158261
158644
  case "fact": return buildSnippetForFact(definition);
158262
158645
  case "color": return buildSnippetForColor();
@@ -158317,6 +158700,15 @@ function buildSnippetForParameter(definition) {
158317
158700
  lines.push(``);
158318
158701
  return lines.join("\n");
158319
158702
  }
158703
+ function buildSnippetForComputedAttribute(definition) {
158704
+ const lines = [];
158705
+ const tb = tabStopBuilder();
158706
+ if (!definition.id) lines.push(`id: ${tb()}`);
158707
+ if (!definition.type) lines.push(`type: computed_attribute`);
158708
+ if (!definition.maql) lines.push(`maql: SELECT CASE WHEN {metric/${tb()}} > ${tb("0")} THEN "${tb("High")}" ELSE "${tb("Low")}" END`);
158709
+ lines.push(``);
158710
+ return lines.join("\n");
158711
+ }
158320
158712
  function buildSnippetForAttribute(definition) {
158321
158713
  const lines = [];
158322
158714
  const tb = tabStopBuilder();
@@ -159560,6 +159952,7 @@ function referencesFindYamlByType(references, document, parents, nodeItem, seman
159560
159952
  case "required_data_source":
159561
159953
  case "unique_filter_local_identifiers":
159562
159954
  case "unique_tab_identifiers":
159955
+ case "iana_timezone":
159563
159956
  case void 0: return [];
159564
159957
  default: assertUnreachable$1(semanticItem.type);
159565
159958
  }
@@ -159572,6 +159965,7 @@ const REFERENCED_OBJECT_TYPES = {
159572
159965
  "dataSource.id": "dataSource",
159573
159966
  "metric.id": "metric",
159574
159967
  "parameter.id": "parameter",
159968
+ "computedAttribute.id": "computed_attribute",
159575
159969
  "table.id": "table",
159576
159970
  "fact.id": "fact",
159577
159971
  "aggregated_fact.id": "aggregated_fact",
@@ -159595,6 +159989,7 @@ function referencesFindYamlForReferences(references, nodeItem, semanticItem, typ
159595
159989
  case "dataSource.id":
159596
159990
  case "metric.id":
159597
159991
  case "parameter.id":
159992
+ case "computedAttribute.id":
159598
159993
  case "table.id":
159599
159994
  case "fact.id":
159600
159995
  case "aggregated_fact.id":
@@ -159699,6 +160094,9 @@ function referencesFindYamlForDefinition(references, parents, nodeItem, semantic
159699
160094
  case "dashboard.id":
159700
160095
  prev.push(...createDefinitionForMainType(references, isDashboard, value, "dashboard"));
159701
160096
  break;
160097
+ case "computedAttribute.id":
160098
+ prev.push(...createDefinitionForMainType(references, isComputedAttribute, value, "computed_attribute"));
160099
+ break;
159702
160100
  case "metric.id":
159703
160101
  prev.push(...createDefinitionForMainType(references, isMetric, value, "metric"));
159704
160102
  break;
@@ -160225,6 +160623,7 @@ function createTextEdit(item, name) {
160225
160623
  case "dataSource":
160226
160624
  case "metric":
160227
160625
  case "parameter":
160626
+ case "computed_attribute":
160228
160627
  case "attribute_hierarchy":
160229
160628
  case "label": {
160230
160629
  const prefix = `${item.type}/`;
@@ -160680,7 +161079,7 @@ async function open(state, emitter, file) {
160680
161079
  //#endregion
160681
161080
  //#region ../code/package.json
160682
161081
  var name = "@gooddata/code";
160683
- var version = "0.50.0-alpha.4";
161082
+ var version = "0.50.0-alpha.6";
160684
161083
  //#endregion
160685
161084
  //#region ../../../sdk/libs/api-client-tiger/src/axios.ts
160686
161085
  /**
@@ -160702,7 +161101,7 @@ const _CONFIG = {
160702
161101
  common: {
160703
161102
  "X-Requested-With": "XMLHttpRequest",
160704
161103
  "X-GDC-JS-PACKAGE": "@gooddata/api-client-tiger",
160705
- "X-GDC-JS-PACKAGE-VERSION": "11.54.0-alpha.4"
161104
+ "X-GDC-JS-PACKAGE-VERSION": "11.54.0-alpha.6"
160706
161105
  },
160707
161106
  post: { "Content-Type": "application/json;charset=utf8" },
160708
161107
  put: { "Content-Type": "application/json;charset=utf8" }
@@ -199222,6 +199621,7 @@ function updateDeclarativeLayout(currentWs, newWs) {
199222
199621
  analytics: {
199223
199622
  ...currentWs.analytics ?? {},
199224
199623
  metrics: newWs.analytics?.metrics,
199624
+ ...newWs.analytics?.computedAttributes ? { computedAttributes: newWs.analytics?.computedAttributes } : {},
199225
199625
  ...newWs.analytics?.visualizationObjects ? { visualizationObjects: newWs.analytics?.visualizationObjects } : {},
199226
199626
  ...newWs.analytics?.analyticalDashboards ? { analyticalDashboards: newWs.analytics?.analyticalDashboards } : {},
199227
199627
  ...newWs.analytics?.filterContexts ? { filterContexts: newWs.analytics?.filterContexts } : {},
@@ -199403,6 +199803,11 @@ function createDeclarativeWorkspaceModel(entities, profile) {
199403
199803
  return data;
199404
199804
  });
199405
199805
  ws.analytics.parameters = parameterEntities.map((d) => d.declarative);
199806
+ const computedAttributesEntities = entities.filter((e) => ComputedAttributeTypes.includes(e.type)).map((data) => {
199807
+ data.declarative = yamlComputedAttributeToDeclarative(data.data);
199808
+ return data;
199809
+ });
199810
+ ws.analytics.computedAttributes = computedAttributesEntities.map((d) => d.declarative);
199406
199811
  const visualisationsEntities = entities.filter((e) => VisualisationsTypes.includes(e.type)).map((data) => {
199407
199812
  data.declarative = yamlVisualisationToDeclarative(entities, data.data);
199408
199813
  return data;
@@ -199676,6 +200081,10 @@ function buildEntities(ws) {
199676
200081
  type: "metric",
199677
200082
  id: metric.id
199678
200083
  })),
200084
+ ...(ws.analytics?.computedAttributes ?? []).map((computedAttribute) => ({
200085
+ type: "computed_attribute",
200086
+ id: computedAttribute.id
200087
+ })),
199679
200088
  ...(ws.analytics?.visualizationObjects ?? []).map((visualisation) => ({
199680
200089
  type: declarativeVisTypeToYaml(visualisation.content),
199681
200090
  id: visualisation.id
@@ -199712,6 +200121,7 @@ async function fromDeclarative(workspace, basePath, profile, { tables = {}, stor
199712
200121
  const datasetsPath = [...basePath, "datasets"];
199713
200122
  const metricsPath = [...basePath, "metrics"];
199714
200123
  const parametersPath = [...basePath, "parameters"];
200124
+ const computedAttributesPath = [...basePath, "computedAttributes"];
199715
200125
  const visualisationsPath = [...basePath, "visualisations"];
199716
200126
  const dashboardsPath = [...basePath, "dashboards"];
199717
200127
  const pluginPath = [...basePath, "plugins"];
@@ -199769,6 +200179,17 @@ async function fromDeclarative(workspace, basePath, profile, { tables = {}, stor
199769
200179
  });
199770
200180
  return createNewFile(store, filePath, createFileContent({ content: Buffer.from(content, "utf8") }), { mode: "remote" });
199771
200181
  }) ?? []);
200182
+ if (workspace?.analytics?.computedAttributes) mergeResults(update, workspace.analytics.computedAttributes.map((computedAttribute) => {
200183
+ const { content, json } = declarativeComputedAttributeToYaml(computedAttribute);
200184
+ const filePath = generateFileName(files, computedAttributesPath, computedAttribute.id, computedAttribute.title);
200185
+ if (json && content) entitiesLoaded.push({
200186
+ type: "computed_attribute",
200187
+ id: computedAttribute.id,
200188
+ data: json,
200189
+ path: filePath
200190
+ });
200191
+ return createNewFile(store, filePath, createFileContent({ content: Buffer.from(content, "utf8") }), { mode: "remote" });
200192
+ }) ?? []);
199772
200193
  if (workspace?.analytics?.visualizationObjects) mergeResults(update, workspace.analytics.visualizationObjects.map((visualisation) => {
199773
200194
  const { content, json } = declarativeVisualisationToYaml(entitiesLoaded, visualisation);
199774
200195
  const filePath = generateFileName(files, visualisationsPath, visualisation.id, visualisation.title);
@@ -202166,6 +202587,7 @@ async function fileExists$2(path) {
202166
202587
  //#endregion
202167
202588
  //#region src/commands/init/file.cursorRules.ts
202168
202589
  const ruleFiles = [
202590
+ "computedAttributes.mdc",
202169
202591
  "dashboards.mdc",
202170
202592
  "datasets.mdc",
202171
202593
  "gooddata.mdc",