@snabcentr/client-core 4.8.0 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import * as i1 from 'rxjs';
2
2
  import { of, startWith as startWith$1, Subject, ReplaySubject, partition, combineLatest, map as map$1, debounceTime, switchMap, tap, filter, shareReplay, distinctUntilChanged, BehaviorSubject, materialize, dematerialize, merge, distinctUntilKeyChanged, skip, first, catchError as catchError$1, throwError, expand, takeWhile, toArray, EMPTY, take, defaultIfEmpty, concatMap, finalize, takeUntil, timeout, interval, share, scan } from 'rxjs';
3
3
  import { map, startWith, catchError } from 'rxjs/operators';
4
4
  import { parseISO, parse, isValid, format } from 'date-fns';
5
- import { isString, isNil, isObject, isDate, isMatch, isArray, get, isNumber, isBoolean } from 'lodash-es';
5
+ import { isString, isNil, isObject, isDate, isMatch, isArray, omit, get, isNumber, isBoolean } from 'lodash-es';
6
6
  import * as i0 from '@angular/core';
7
7
  import { InjectionToken, inject, PLATFORM_ID, Inject, Optional, Injectable, EventEmitter, DestroyRef, LOCALE_ID, Pipe, RESPONSE_INIT, RendererFactory2 } from '@angular/core';
8
8
  import { WA_LOCAL_STORAGE, WA_USER_AGENT, WA_WINDOW } from '@ng-web-apis/common';
@@ -7635,36 +7635,36 @@ class SchemaOrgFactory {
7635
7635
  *
7636
7636
  * @param product Данные о продукте.
7637
7637
  * @param productPath Url путь к товару. В пути должен присутствовать шаблон ':id', обозначающий идентификатор товара для подстановки.
7638
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7638
7639
  */
7639
- generateForProductItem(product, productPath) {
7640
+ generateForProductItem(product, productPath, id) {
7640
7641
  const productUrl = `${this.urls.siteUrl}${productPath.replace(':id', this.idOrSlugPipe.transform(product).toString())}`;
7641
7642
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7642
- const image = this.mediaImageTransformerPipe.transform(product?.getImagePreview() ?? product.image, true);
7643
+ const image = this.mediaImageTransformerPipe.transform(product?.getImagePreview?.() ?? product.image, true);
7643
7644
  const description = product.properties?.description;
7644
7645
  const priceValidUntil = this.normalizePriceValidUntil(product.discount?.expiredAt);
7645
7646
  return {
7646
7647
  '@context': 'https://schema.org',
7647
7648
  '@type': 'Product',
7649
+ ...(id && { '@id': id }),
7648
7650
  name: product.name,
7649
7651
  ...(image && { image }),
7650
7652
  ...(description && { description }),
7651
7653
  mpn: product.code,
7652
7654
  url: productUrl,
7653
- offers: [
7654
- {
7655
- '@type': 'Offer',
7656
- priceCurrency: 'RUB',
7657
- ...(priceValidUntil && { priceValidUntil }),
7658
- price: product.costRub,
7659
- availability: this.getAvailability(product),
7660
- itemCondition: 'https://schema.org/NewCondition',
7661
- seller: {
7662
- '@type': 'Organization',
7663
- name: this.companyInfo.name,
7664
- },
7665
- url: productUrl,
7655
+ offers: {
7656
+ '@type': 'Offer',
7657
+ priceCurrency: 'RUB',
7658
+ ...(priceValidUntil && { priceValidUntil }),
7659
+ price: product.costRub,
7660
+ availability: this.getAvailability(product),
7661
+ itemCondition: 'https://schema.org/NewCondition',
7662
+ seller: {
7663
+ '@type': 'Organization',
7664
+ name: this.companyInfo.name,
7666
7665
  },
7667
- ],
7666
+ url: productUrl,
7667
+ },
7668
7668
  };
7669
7669
  }
7670
7670
  /**
@@ -7675,13 +7675,15 @@ class SchemaOrgFactory {
7675
7675
  * @param categoryPath Url путь к категориям товаров. В пути должен присутствовать шаблон ':id', обозначающий идентификатор категории для подстановки.
7676
7676
  * @param productPath Url путь к товару. В пути должен присутствовать шаблон ':id', обозначающий идентификатор товара для подстановки.
7677
7677
  * @param breadcrumbs Данные о хлебных крошках для категории.
7678
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7678
7679
  */
7679
- generateForCategoryItem(category, products, categoryPath, productPath, breadcrumbs) {
7680
+ generateForCategoryItem(category, products, categoryPath, productPath, breadcrumbs, id) {
7680
7681
  const description = category.seo?.description ?? category.properties?.description;
7681
7682
  const image = this.mediaImageTransformerPipe.transform(category.image, true);
7682
7683
  return {
7683
7684
  '@context': 'https://schema.org',
7684
7685
  '@type': 'CollectionPage',
7686
+ ...(id && { '@id': id }),
7685
7687
  name: category.seo?.title ?? category.name,
7686
7688
  ...(description && { description }),
7687
7689
  url: this.getCategoryCanonicalUrl(category, categoryPath),
@@ -7699,12 +7701,6 @@ class SchemaOrgFactory {
7699
7701
  name: category.name,
7700
7702
  ...(description && { description }),
7701
7703
  },
7702
- // Информация о сайте.
7703
- isPartOf: {
7704
- '@type': 'WebSite',
7705
- name: this.companyInfo.name,
7706
- url: this.urls.siteUrl,
7707
- },
7708
7704
  // Связанные страницы.
7709
7705
  relatedLink: [
7710
7706
  `${this.urls.siteUrl}${categoryPath.replace(':id', '')}`,
@@ -7745,6 +7741,223 @@ class SchemaOrgFactory {
7745
7741
  ],
7746
7742
  };
7747
7743
  }
7744
+ /**
7745
+ * Генерирует и возвращает схему данных OnlineStore на основе данных компании из окружения.
7746
+ */
7747
+ // eslint-disable-next-line sonarjs/function-return-type
7748
+ generateForOrganization() {
7749
+ const postalAddress = this.createPostalAddress(this.companyInfo.address);
7750
+ return {
7751
+ '@context': 'https://schema.org',
7752
+ '@type': 'OnlineStore',
7753
+ '@id': `${this.urls.siteUrl}#organization`,
7754
+ name: this.companyInfo.name,
7755
+ legalName: this.companyInfo.name,
7756
+ url: this.urls.siteUrl,
7757
+ logo: this.urls.logoUrl,
7758
+ image: this.urls.logoUrl,
7759
+ email: this.companyInfo.mail,
7760
+ telephone: this.companyInfo.phone,
7761
+ ...(postalAddress && { address: postalAddress }),
7762
+ legalAddress: this.createPostalAddress({ streetAddress: this.companyInfo.legalAddress }),
7763
+ // TODO: Перечислить все розничные магазины.
7764
+ // hasPOS: [],
7765
+ taxID: this.companyInfo.inn,
7766
+ identifier: {
7767
+ '@type': 'PropertyValue',
7768
+ propertyID: 'OGRN',
7769
+ value: this.companyInfo.ogrn,
7770
+ },
7771
+ contactPoint: this.createOrganizationContactPoints(),
7772
+ ...(this.companyInfo.warehouseAddress.length > 0 && {
7773
+ location: this.companyInfo.warehouseAddress.map((warehouseAddress) => ({
7774
+ '@type': 'Place',
7775
+ name: `${this.companyInfo.name} — склад самовывоза`,
7776
+ address: warehouseAddress,
7777
+ })),
7778
+ }),
7779
+ };
7780
+ }
7781
+ /**
7782
+ * Генерирует и возвращает схему данных для указанной новости.
7783
+ *
7784
+ * @param news Данные о новости.
7785
+ * @param newsPath Url путь к новости. В пути должен присутствовать шаблон ':id', обозначающий идентификатор новости для подстановки.
7786
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7787
+ */
7788
+ generateForNewsArticle(news, newsPath, id) {
7789
+ const newsUrl = `${this.urls.siteUrl}${newsPath.replace(':id', news.id.toString())}`;
7790
+ const image = this.mediaImageTransformerPipe.transform(news.image, true);
7791
+ const headline = news.seo?.title ?? news.subject;
7792
+ const description = news.seo?.description;
7793
+ const datePublished = this.normalizeSchemaDate(news.createdAt);
7794
+ const articleBody = news.text ? this.stripHtml(news.text) : undefined;
7795
+ return {
7796
+ '@context': 'https://schema.org',
7797
+ '@type': 'NewsArticle',
7798
+ ...(id && { '@id': id }),
7799
+ headline,
7800
+ ...(description && { description }),
7801
+ ...(image && { image }),
7802
+ ...(datePublished && { datePublished }),
7803
+ ...(articleBody && { articleBody }),
7804
+ url: newsUrl,
7805
+ mainEntityOfPage: newsUrl,
7806
+ author: {
7807
+ '@type': 'Organization',
7808
+ name: this.companyInfo.name,
7809
+ url: this.urls.siteUrl,
7810
+ },
7811
+ publisher: {
7812
+ '@type': 'Organization',
7813
+ name: this.companyInfo.name,
7814
+ logo: {
7815
+ '@type': 'ImageObject',
7816
+ url: this.urls.logoUrl,
7817
+ },
7818
+ },
7819
+ };
7820
+ }
7821
+ /**
7822
+ * Генерирует и возвращает схему данных FAQPage для страницы с вопросами и ответами.
7823
+ *
7824
+ * @param items Список вопросов и ответов.
7825
+ * @param pagePath Url путь к странице FAQ.
7826
+ * @param pageName Необязательное название страницы.
7827
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7828
+ */
7829
+ generateForFaqPage(items, pagePath, pageName, id) {
7830
+ const pageUrl = `${this.urls.siteUrl}${pagePath}`;
7831
+ return {
7832
+ '@context': 'https://schema.org',
7833
+ '@type': 'FAQPage',
7834
+ ...(id && { '@id': id }),
7835
+ ...(pageName && { name: pageName }),
7836
+ url: pageUrl,
7837
+ mainEntity: items.map((item) => ({
7838
+ '@type': 'Question',
7839
+ name: item.question,
7840
+ acceptedAnswer: {
7841
+ '@type': 'Answer',
7842
+ text: this.stripHtml(item.answer),
7843
+ },
7844
+ })),
7845
+ };
7846
+ }
7847
+ /**
7848
+ * Объединяет несколько JSON-LD сущностей в один документ с `@graph`.
7849
+ *
7850
+ * @param data Массив JSON-LD сущностей для объединения.
7851
+ */
7852
+ // eslint-disable-next-line class-methods-use-this,sonarjs/function-return-type
7853
+ merge(data) {
7854
+ return {
7855
+ '@context': 'https://schema.org',
7856
+ '@graph': data.map((item) => omit(item, '@context')),
7857
+ };
7858
+ }
7859
+ /**
7860
+ * Формирует PostalAddress из структурированного адреса компании.
7861
+ *
7862
+ * @param address Структурированный адрес компании.
7863
+ */
7864
+ // eslint-disable-next-line class-methods-use-this
7865
+ createPostalAddress(address) {
7866
+ const streetAddress = [address.streetAddress, address.extendedAddress].filter(Boolean).join(', ');
7867
+ if (!streetAddress && !address.locality && !address.region && !address.postalCode && !address.country) {
7868
+ return undefined;
7869
+ }
7870
+ return {
7871
+ '@type': 'PostalAddress',
7872
+ ...(streetAddress && { streetAddress }),
7873
+ ...(address.locality && { addressLocality: address.locality }),
7874
+ ...(address.region && { addressRegion: address.region }),
7875
+ ...(address.postalCode && { postalCode: address.postalCode }),
7876
+ ...(address.country && { addressCountry: address.country }),
7877
+ };
7878
+ }
7879
+ /**
7880
+ * Формирует список ContactPoint для Organization.
7881
+ */
7882
+ createOrganizationContactPoints() {
7883
+ const contactPoints = [
7884
+ {
7885
+ '@type': 'ContactPoint',
7886
+ contactType: 'customer service',
7887
+ telephone: this.companyInfo.phone,
7888
+ email: this.companyInfo.mail,
7889
+ areaServed: 'RU',
7890
+ availableLanguage: 'Russian',
7891
+ },
7892
+ ];
7893
+ if (this.companyInfo.secondaryPhone) {
7894
+ contactPoints.push({
7895
+ '@type': 'ContactPoint',
7896
+ contactType: 'customer service',
7897
+ telephone: this.companyInfo.secondaryPhone,
7898
+ areaServed: 'RU',
7899
+ availableLanguage: 'Russian',
7900
+ });
7901
+ }
7902
+ if (this.companyInfo.hr) {
7903
+ contactPoints.push({
7904
+ '@type': 'ContactPoint',
7905
+ contactType: 'HR',
7906
+ telephone: this.companyInfo.hr.phone,
7907
+ email: this.companyInfo.hr.mail,
7908
+ areaServed: 'RU',
7909
+ availableLanguage: 'Russian',
7910
+ });
7911
+ }
7912
+ return contactPoints;
7913
+ }
7914
+ /**
7915
+ * Удаляет HTML-разметку из текста.
7916
+ *
7917
+ * @param html Текст с HTML-разметкой.
7918
+ */
7919
+ // eslint-disable-next-line class-methods-use-this
7920
+ stripHtml(html) {
7921
+ const withoutTags = html
7922
+ .split('<')
7923
+ .map((part, index) => {
7924
+ if (index === 0) {
7925
+ return part;
7926
+ }
7927
+ const closeTagIndex = part.indexOf('>');
7928
+ return closeTagIndex === -1 ? part : ` ${part.slice(closeTagIndex + 1)}`;
7929
+ })
7930
+ .join('');
7931
+ return withoutTags
7932
+ .replaceAll(/\s+/g, ' ')
7933
+ .replaceAll(/ ([.,!?;:])/g, '$1')
7934
+ .trim();
7935
+ }
7936
+ /**
7937
+ * Нормализует дату в формат Schema.org (ISO 8601).
7938
+ *
7939
+ * @param dateValue Дата для нормализации.
7940
+ */
7941
+ // eslint-disable-next-line class-methods-use-this
7942
+ normalizeSchemaDate(dateValue) {
7943
+ if (!dateValue) {
7944
+ return undefined;
7945
+ }
7946
+ if (/^\d{4}-\d{2}-\d{2}/.test(dateValue)) {
7947
+ return dateValue;
7948
+ }
7949
+ const withTimeMatch = /^(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2})$/.exec(dateValue);
7950
+ if (withTimeMatch) {
7951
+ const [, day, month, year, hours, minutes] = withTimeMatch;
7952
+ return `${year}-${month}-${day}T${hours}:${minutes}:00`;
7953
+ }
7954
+ const dateOnlyMatch = /^(\d{2})\.(\d{2})\.(\d{4})$/.exec(dateValue);
7955
+ if (!dateOnlyMatch) {
7956
+ return undefined;
7957
+ }
7958
+ const [, day, month, year] = dateOnlyMatch;
7959
+ return `${year}-${month}-${day}`;
7960
+ }
7748
7961
  /**
7749
7962
  * Нормализует дату окончания цены в формат Schema.org (YYYY-MM-DD).
7750
7963
  *
@@ -7766,9 +7979,9 @@ class SchemaOrgFactory {
7766
7979
  // eslint-disable-next-line class-methods-use-this
7767
7980
  getAvailability(product) {
7768
7981
  if (product.onOrder) {
7769
- return 'PreOrder';
7982
+ return 'https://schema.org/PreOrder';
7770
7983
  }
7771
- return product.stockCount?.length ? 'InStock' : 'OutOfStock';
7984
+ return product.stockCount?.length ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
7772
7985
  }
7773
7986
  /**
7774
7987
  * Проверяет, является ли категория виртуальной.
@@ -7812,21 +8025,19 @@ class SchemaOrgFactory {
7812
8025
  url: productUrl,
7813
8026
  ...(image && { image }),
7814
8027
  ...(description && { description }),
7815
- offers: [
7816
- {
7817
- '@type': 'Offer',
7818
- priceCurrency: 'RUB',
7819
- ...(priceValidUntil && { priceValidUntil }),
7820
- price: product.costRub,
7821
- availability: this.getAvailability(product),
7822
- itemCondition: 'https://schema.org/NewCondition',
7823
- seller: {
7824
- '@type': 'Organization',
7825
- name: this.companyInfo.name,
7826
- },
7827
- url: productUrl,
8028
+ offers: {
8029
+ '@type': 'Offer',
8030
+ priceCurrency: 'RUB',
8031
+ ...(priceValidUntil && { priceValidUntil }),
8032
+ price: product.costRub,
8033
+ availability: this.getAvailability(product),
8034
+ itemCondition: 'https://schema.org/NewCondition',
8035
+ seller: {
8036
+ '@type': 'Organization',
8037
+ name: this.companyInfo.name,
7828
8038
  },
7829
- ],
8039
+ url: productUrl,
8040
+ },
7830
8041
  },
7831
8042
  };
7832
8043
  }
@@ -7848,14 +8059,21 @@ class SchemaOrgFactory {
7848
8059
  itemListOrder: 'https://schema.org/ItemListUnordered',
7849
8060
  itemListElement: [
7850
8061
  // Добавляем подкатегории в начало списка.
7851
- ...childCategories.slice(0, 5).map((subCategory, index) => ({
7852
- '@type': 'ListItem',
7853
- position: index + 1,
7854
- name: subCategory.name,
7855
- url: this.getCategoryCanonicalUrl(subCategory, categoryPath),
7856
- image: this.mediaImageTransformerPipe.transform(subCategory.image, true),
7857
- description: subCategory.seo?.description ?? subCategory.properties?.description,
7858
- })),
8062
+ ...childCategories.slice(0, 5).map((subCategory, index) => {
8063
+ const image = this.mediaImageTransformerPipe.transform(subCategory.image, true);
8064
+ const description = subCategory.seo?.description ?? subCategory.properties?.description;
8065
+ return {
8066
+ '@type': 'ListItem',
8067
+ position: index + 1,
8068
+ item: {
8069
+ '@type': 'CollectionPage',
8070
+ name: subCategory.name,
8071
+ url: this.getCategoryCanonicalUrl(subCategory, categoryPath),
8072
+ ...(image && { image }),
8073
+ ...(description && { description }),
8074
+ },
8075
+ };
8076
+ }),
7859
8077
  // Добавляем товары после подкатегорий.
7860
8078
  ...products.slice(0, 10).map((product, index) => this.createProductsListItem(product, childCategories.length + index + 1, productPath)),
7861
8079
  ],
@@ -7868,37 +8086,46 @@ class SchemaOrgFactory {
7868
8086
  * @param categoryPath Url путь к категориям товаров. В пути должен присутствовать шаблон ':id', обозначающий идентификатор категории для подстановки.
7869
8087
  */
7870
8088
  createCatalogBreadcrumbsList(breadcrumbs, categoryPath) {
8089
+ const catalogUrl = `${this.urls.siteUrl}${categoryPath.replace(':id', '')}`;
7871
8090
  const breadcrumbItems = [
7872
8091
  // Всегда добавляем главную страницу.
7873
- {
7874
- '@type': 'ListItem',
7875
- position: 1,
7876
- name: 'Главная',
7877
- item: this.urls.siteUrl,
7878
- },
8092
+ this.createBreadcrumbListItem(1, 'Главная', this.urls.siteUrl),
7879
8093
  // Добавляем каталог.
7880
- {
7881
- '@type': 'ListItem',
7882
- position: 2,
7883
- name: 'Каталог',
7884
- item: `${this.urls.siteUrl}/${categoryPath}`,
7885
- },
8094
+ this.createBreadcrumbListItem(2, 'Каталог', catalogUrl),
7886
8095
  ];
7887
8096
  // Добавляем существующие breadcrumbs с корректировкой позиций.
7888
8097
  breadcrumbs.forEach((item, index) => {
7889
8098
  const link = isArray(item.routerLink) ? item.routerLink.join('/') : item.routerLink;
7890
- breadcrumbItems.push({
7891
- '@type': 'ListItem',
7892
- position: index + 3, // Начинаем с позиции 3 (после Главная и Каталог).
7893
- name: item.label,
7894
- item: link ? `${this.urls.siteUrl}/${link}` : undefined,
7895
- });
8099
+ breadcrumbItems.push(this.createBreadcrumbListItem(index + 3, item.label, link ? `${this.urls.siteUrl}/${link}` : undefined));
7896
8100
  });
7897
8101
  return {
7898
8102
  '@type': 'BreadcrumbList',
8103
+ itemListOrder: 'https://schema.org/ItemListOrderAscending',
7899
8104
  itemListElement: breadcrumbItems,
7900
8105
  };
7901
8106
  }
8107
+ /**
8108
+ * Создаёт элемент BreadcrumbList в формате, рекомендованном Schema.org.
8109
+ *
8110
+ * @param position Позиция элемента в цепочке.
8111
+ * @param name Название элемента.
8112
+ * @param url URL элемента.
8113
+ */
8114
+ // eslint-disable-next-line class-methods-use-this
8115
+ createBreadcrumbListItem(position, name, url) {
8116
+ return {
8117
+ '@type': 'ListItem',
8118
+ position,
8119
+ ...(url
8120
+ ? {
8121
+ item: {
8122
+ '@id': url,
8123
+ name,
8124
+ },
8125
+ }
8126
+ : { name }),
8127
+ };
8128
+ }
7902
8129
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SchemaOrgFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7903
8130
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SchemaOrgFactory, providedIn: 'root' }); }
7904
8131
  }
@@ -7954,6 +8181,10 @@ class ScSeoService {
7954
8181
  * Объект {@link Document}, предоставляющий доступ к DOM страницы.
7955
8182
  */
7956
8183
  this.document = inject(DOCUMENT);
8184
+ /**
8185
+ * Фабрика для создания данных Schema.org.
8186
+ */
8187
+ this.schemaOrgFactory = inject(SchemaOrgFactory);
7957
8188
  /**
7958
8189
  * Фабрика для создания экземпляров {@link Renderer2}.
7959
8190
  */
@@ -7969,8 +8200,9 @@ class ScSeoService {
7969
8200
  * @param resource Ресурс на основе которого необходимо установить мета-теги.
7970
8201
  * @param img Изображение. Если не пришло, то будет установлено значение по умолчанию.
7971
8202
  * @param robots Список robots-тегов для страницы.
8203
+ * @param schemaOrgData Данные Schema.org для встраивания на странице.
7972
8204
  */
7973
- setFromResource(resource, img = this.urls.logoUrl, robots = ['index', 'follow']) {
8205
+ setFromResource(resource, img, robots, schemaOrgData) {
7974
8206
  const updatedResource = {
7975
8207
  title: this.replaceTemplates(resource?.title ?? this.defaultSeo.title, resource?.instanceData ?? {}),
7976
8208
  description: this.replaceTemplates(resource?.description ?? this.defaultSeo.description, resource?.instanceData ?? {}),
@@ -7978,21 +8210,24 @@ class ScSeoService {
7978
8210
  meta: resource?.meta ?? [],
7979
8211
  };
7980
8212
  const url = `${this.urls.siteUrl}${this.router.url}`;
7981
- this.setMetaTags(updatedResource.title, updatedResource.description, updatedResource.keywords, updatedResource.meta, robots);
7982
- this.setOpenGraphMetaTags(updatedResource.title, updatedResource.description, url, img);
8213
+ this.setMetaTags(updatedResource.title, updatedResource.description, updatedResource.keywords, updatedResource.meta, robots ?? ['index', 'follow']);
8214
+ this.setOpenGraphMetaTags(updatedResource.title, updatedResource.description, url, img ?? this.urls.logoUrl);
7983
8215
  this.setCanonicalLink(url);
8216
+ // Устанавливаем Schema.org параметры.
8217
+ this.setSchemaOrgData(this.schemaOrgFactory.merge([this.schemaOrgFactory.generateForOrganization(), ...(schemaOrgData ? [schemaOrgData] : [])]));
7984
8218
  }
7985
8219
  /**
7986
8220
  * Устанавливает seo параметры со значением по умолчанию.
7987
8221
  *
7988
8222
  * @param title Заголовок страницы.
7989
8223
  * @param robots Список robots тегов для страницы.
8224
+ * @param schemaOrgData Данные Schema.org для встраивания на странице.
7990
8225
  */
7991
- setByDefault(title, robots = ['index', 'follow']) {
8226
+ setByDefault(title, robots, schemaOrgData) {
7992
8227
  this.setFromResource({
7993
8228
  title: `${title ?? this.defaultSeo.title} - ${this.companyInfo.name}`,
7994
8229
  description: title ? `${title}, ${this.defaultSeo.description}` : this.defaultSeo.description,
7995
- }, this.urls.logoUrl, robots);
8230
+ }, this.urls.logoUrl, robots ?? ['index', 'follow'], schemaOrgData);
7996
8231
  }
7997
8232
  /**
7998
8233
  * Устанавливает seo параметры со значением по умолчанию. Устанавливает значение "не индексировать" для поисковых роботов.
@@ -8023,9 +8258,7 @@ class ScSeoService {
8023
8258
  this.setOpenGraphMetaTags(title, description, url, this.mediaImageTransformerPipe.transform(item.image, true));
8024
8259
  this.setCanonicalLink(url);
8025
8260
  // Устанавливаем Schema.org параметры.
8026
- if (schemaOrgData) {
8027
- this.setSchemaOrgData(schemaOrgData);
8028
- }
8261
+ this.setSchemaOrgData(this.schemaOrgFactory.merge([this.schemaOrgFactory.generateForOrganization(), ...(schemaOrgData ? [schemaOrgData] : [])]));
8029
8262
  }
8030
8263
  /**
8031
8264
  * Заменяет шаблоны в тексте на значения из объекта.