@teleporthq/teleport-plugin-next-data-source 0.43.67 → 0.43.68
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/__tests__/array-overlap-sql.test.ts +53 -0
- package/__tests__/blog-post-page-enrichment.test.ts +214 -0
- package/__tests__/browser-row-policy.test.ts +503 -0
- package/__tests__/data-source-cache-wrapping.test.ts +18 -2
- package/__tests__/ecommerce-product-options.test.ts +206 -0
- package/__tests__/ecommerce-product-pages.test.ts +82 -0
- package/__tests__/ecommerce-product-pre-options.golden.json +505 -0
- package/__tests__/ecommerce-product-storefront-contract.test.ts +293 -0
- package/__tests__/ecommerce-product-subscriptions.test.ts +121 -0
- package/__tests__/fetchers.test.ts +2 -2
- package/__tests__/items-path.test.ts +150 -0
- package/__tests__/product-options-storefront.fixture.json +2510 -0
- package/__tests__/product-page-url-fixtures.json +25 -0
- package/__tests__/product-price-sort.ts +4 -2
- package/__tests__/raw-rows-mode.test.ts +111 -0
- package/__tests__/rest-api-response-cache.test.ts +434 -0
- package/__tests__/table-read-route-protected-tables.test.ts +493 -0
- package/dist/cjs/array-overlap-sql.d.ts +21 -0
- package/dist/cjs/array-overlap-sql.d.ts.map +1 -0
- package/dist/cjs/array-overlap-sql.js +25 -0
- package/dist/cjs/array-overlap-sql.js.map +1 -0
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
- package/dist/cjs/data-source-fetchers.js +10 -4
- package/dist/cjs/data-source-fetchers.js.map +1 -1
- package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
- package/dist/cjs/fetchers/javascript.js +1 -1
- package/dist/cjs/fetchers/javascript.js.map +1 -1
- package/dist/cjs/fetchers/postgresql.d.ts +1 -1
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
- package/dist/cjs/fetchers/postgresql.js +8 -4
- package/dist/cjs/fetchers/postgresql.js.map +1 -1
- package/dist/cjs/fetchers/raw-query.d.ts +8 -1
- package/dist/cjs/fetchers/raw-query.d.ts.map +1 -1
- package/dist/cjs/fetchers/raw-query.js +42 -4
- package/dist/cjs/fetchers/raw-query.js.map +1 -1
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
- package/dist/cjs/fetchers/rest-api.js +7 -2
- package/dist/cjs/fetchers/rest-api.js.map +1 -1
- package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
- package/dist/cjs/fetchers/teleport.js +8 -5
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts +43 -0
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/browser-row-policy.js +66 -0
- package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -0
- package/dist/cjs/fetchers/utils/request-sql-guards.d.ts +8 -0
- package/dist/cjs/fetchers/utils/request-sql-guards.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/request-sql-guards.js +12 -0
- package/dist/cjs/fetchers/utils/request-sql-guards.js.map +1 -0
- package/dist/cjs/fetchers/utils/rest-api-response-cache.d.ts +40 -0
- package/dist/cjs/fetchers/utils/rest-api-response-cache.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/rest-api-response-cache.js +64 -0
- package/dist/cjs/fetchers/utils/rest-api-response-cache.js.map +1 -0
- package/dist/cjs/fetchers/utils/table-access-guard.d.ts +23 -0
- package/dist/cjs/fetchers/utils/table-access-guard.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/table-access-guard.js +34 -0
- package/dist/cjs/fetchers/utils/table-access-guard.js.map +1 -0
- package/dist/cjs/items-path.d.ts +10 -0
- package/dist/cjs/items-path.d.ts.map +1 -0
- package/dist/cjs/items-path.js +86 -0
- package/dist/cjs/items-path.js.map +1 -0
- package/dist/cjs/localized-columns.d.ts.map +1 -1
- package/dist/cjs/localized-columns.js +13 -0
- package/dist/cjs/localized-columns.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +17 -5
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts +16 -0
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts.map +1 -0
- package/dist/cjs/transformations/blog-adjacent-posts.js +25 -0
- package/dist/cjs/transformations/blog-adjacent-posts.js.map +1 -0
- package/dist/cjs/transformations/blog-comments.d.ts +30 -0
- package/dist/cjs/transformations/blog-comments.d.ts.map +1 -0
- package/dist/cjs/transformations/blog-comments.js +34 -0
- package/dist/cjs/transformations/blog-comments.js.map +1 -0
- package/dist/cjs/transformations/blog-post.d.ts +2 -0
- package/dist/cjs/transformations/blog-post.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-post.js +4 -1
- package/dist/cjs/transformations/blog-post.js.map +1 -1
- package/dist/cjs/transformations/ecommerce-product.d.ts +9 -1
- package/dist/cjs/transformations/ecommerce-product.d.ts.map +1 -1
- package/dist/cjs/transformations/ecommerce-product.js +28 -1
- package/dist/cjs/transformations/ecommerce-product.js.map +1 -1
- package/dist/cjs/transformations/heading-anchors.d.ts +25 -0
- package/dist/cjs/transformations/heading-anchors.d.ts.map +1 -0
- package/dist/cjs/transformations/heading-anchors.js +29 -0
- package/dist/cjs/transformations/heading-anchors.js.map +1 -0
- package/dist/cjs/transformations/index.d.ts +47 -4
- package/dist/cjs/transformations/index.d.ts.map +1 -1
- package/dist/cjs/transformations/index.js +56 -18
- package/dist/cjs/transformations/index.js.map +1 -1
- package/dist/cjs/transformations/shared-utils.d.ts.map +1 -1
- package/dist/cjs/transformations/shared-utils.js +1 -1
- package/dist/cjs/transformations/shared-utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +1 -1
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/array-overlap-sql.d.ts +21 -0
- package/dist/esm/array-overlap-sql.d.ts.map +1 -0
- package/dist/esm/array-overlap-sql.js +21 -0
- package/dist/esm/array-overlap-sql.js.map +1 -0
- package/dist/esm/data-source-fetchers.d.ts.map +1 -1
- package/dist/esm/data-source-fetchers.js +11 -5
- package/dist/esm/data-source-fetchers.js.map +1 -1
- package/dist/esm/fetchers/javascript.d.ts.map +1 -1
- package/dist/esm/fetchers/javascript.js +1 -1
- package/dist/esm/fetchers/javascript.js.map +1 -1
- package/dist/esm/fetchers/postgresql.d.ts +1 -1
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
- package/dist/esm/fetchers/postgresql.js +8 -4
- package/dist/esm/fetchers/postgresql.js.map +1 -1
- package/dist/esm/fetchers/raw-query.d.ts +8 -1
- package/dist/esm/fetchers/raw-query.d.ts.map +1 -1
- package/dist/esm/fetchers/raw-query.js +42 -4
- package/dist/esm/fetchers/raw-query.js.map +1 -1
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
- package/dist/esm/fetchers/rest-api.js +7 -2
- package/dist/esm/fetchers/rest-api.js.map +1 -1
- package/dist/esm/fetchers/teleport.d.ts.map +1 -1
- package/dist/esm/fetchers/teleport.js +8 -5
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts +43 -0
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/browser-row-policy.js +60 -0
- package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -0
- package/dist/esm/fetchers/utils/request-sql-guards.d.ts +8 -0
- package/dist/esm/fetchers/utils/request-sql-guards.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/request-sql-guards.js +8 -0
- package/dist/esm/fetchers/utils/request-sql-guards.js.map +1 -0
- package/dist/esm/fetchers/utils/rest-api-response-cache.d.ts +40 -0
- package/dist/esm/fetchers/utils/rest-api-response-cache.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/rest-api-response-cache.js +59 -0
- package/dist/esm/fetchers/utils/rest-api-response-cache.js.map +1 -0
- package/dist/esm/fetchers/utils/table-access-guard.d.ts +23 -0
- package/dist/esm/fetchers/utils/table-access-guard.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/table-access-guard.js +29 -0
- package/dist/esm/fetchers/utils/table-access-guard.js.map +1 -0
- package/dist/esm/items-path.d.ts +10 -0
- package/dist/esm/items-path.d.ts.map +1 -0
- package/dist/esm/items-path.js +58 -0
- package/dist/esm/items-path.js.map +1 -0
- package/dist/esm/localized-columns.d.ts.map +1 -1
- package/dist/esm/localized-columns.js +13 -0
- package/dist/esm/localized-columns.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +17 -5
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/transformations/blog-adjacent-posts.d.ts +16 -0
- package/dist/esm/transformations/blog-adjacent-posts.d.ts.map +1 -0
- package/dist/esm/transformations/blog-adjacent-posts.js +21 -0
- package/dist/esm/transformations/blog-adjacent-posts.js.map +1 -0
- package/dist/esm/transformations/blog-comments.d.ts +30 -0
- package/dist/esm/transformations/blog-comments.d.ts.map +1 -0
- package/dist/esm/transformations/blog-comments.js +30 -0
- package/dist/esm/transformations/blog-comments.js.map +1 -0
- package/dist/esm/transformations/blog-post.d.ts +2 -0
- package/dist/esm/transformations/blog-post.d.ts.map +1 -1
- package/dist/esm/transformations/blog-post.js +4 -1
- package/dist/esm/transformations/blog-post.js.map +1 -1
- package/dist/esm/transformations/ecommerce-product.d.ts +9 -1
- package/dist/esm/transformations/ecommerce-product.d.ts.map +1 -1
- package/dist/esm/transformations/ecommerce-product.js +29 -2
- package/dist/esm/transformations/ecommerce-product.js.map +1 -1
- package/dist/esm/transformations/heading-anchors.d.ts +25 -0
- package/dist/esm/transformations/heading-anchors.d.ts.map +1 -0
- package/dist/esm/transformations/heading-anchors.js +25 -0
- package/dist/esm/transformations/heading-anchors.js.map +1 -0
- package/dist/esm/transformations/index.d.ts +47 -4
- package/dist/esm/transformations/index.d.ts.map +1 -1
- package/dist/esm/transformations/index.js +56 -18
- package/dist/esm/transformations/index.js.map +1 -1
- package/dist/esm/transformations/shared-utils.d.ts.map +1 -1
- package/dist/esm/transformations/shared-utils.js +1 -1
- package/dist/esm/transformations/shared-utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +1 -1
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/array-overlap-sql.ts +41 -0
- package/src/data-source-fetchers.ts +41 -5
- package/src/fetchers/javascript.ts +9 -1
- package/src/fetchers/postgresql.ts +37 -10
- package/src/fetchers/raw-query.ts +60 -5
- package/src/fetchers/rest-api.ts +27 -5
- package/src/fetchers/teleport.ts +37 -13
- package/src/fetchers/utils/browser-row-policy.ts +212 -0
- package/src/fetchers/utils/request-sql-guards.ts +25 -0
- package/src/fetchers/utils/rest-api-response-cache.ts +188 -0
- package/src/fetchers/utils/table-access-guard.ts +39 -0
- package/src/items-path.ts +74 -0
- package/src/localized-columns.ts +13 -0
- package/src/pagination-plugin.ts +29 -7
- package/src/transformations/blog-adjacent-posts.ts +74 -0
- package/src/transformations/blog-comments.ts +132 -0
- package/src/transformations/blog-post.ts +38 -5
- package/src/transformations/ecommerce-product.ts +568 -5
- package/src/transformations/heading-anchors.ts +85 -0
- package/src/transformations/index.ts +165 -22
- package/src/transformations/shared-utils.ts +6 -0
- package/src/utils.ts +26 -4
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The class of the `#` link added to a post's content headings.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ PAIRED with `BLOG_HEADING_ANCHOR_CLASS` in teleport-gui
|
|
5
|
+
* `features/blog/constants/blog-heading-anchors.ts`, whose stylesheet (shipped
|
|
6
|
+
* on the post page) is what keeps the link out of sight until the heading is
|
|
7
|
+
* hovered or focused.
|
|
8
|
+
*/
|
|
9
|
+
export var BLOG_HEADING_ANCHOR_CLASS = 'tq-heading-anchor';
|
|
10
|
+
/**
|
|
11
|
+
* Generates `addHeadingAnchors(html)`: every `<h2>`–`<h6>` of a post's content
|
|
12
|
+
* gets an `id` (kept when it already has one, otherwise a slug of its text,
|
|
13
|
+
* unique within the post) and a trailing `#` link to itself, so a section can
|
|
14
|
+
* be linked to (`/blog/post#setup`) and the link works on the very first load —
|
|
15
|
+
* the ids are in the server-rendered HTML.
|
|
16
|
+
*
|
|
17
|
+
* The link repeats the heading a screen reader already announces, so it is
|
|
18
|
+
* hidden from assistive technology and left out of the tab order; the heading
|
|
19
|
+
* stays the landmark.
|
|
20
|
+
*
|
|
21
|
+
* Idempotent: a heading that already carries the link is left alone. `h1` is
|
|
22
|
+
* the post title's level and is never touched.
|
|
23
|
+
*/
|
|
24
|
+
export var generateHeadingAnchorsCode = function () { return "\nvar BLOG_HEADING_ANCHOR_CLASS = '".concat(BLOG_HEADING_ANCHOR_CLASS, "'\nvar BLOG_HEADING_ID_PATTERN = /\\sid\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/i\n\nfunction escapeHeadingAttribute(value) {\n return String(value)\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n}\n\nfunction blogHeadingSlug(text, used) {\n var base = String(text || '')\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n if (!base) base = 'section'\n var slug = base\n var suffix = 2\n while (used[slug]) {\n slug = base + '-' + suffix\n suffix++\n }\n used[slug] = true\n return slug\n}\n\nfunction addHeadingAnchors(html) {\n if (typeof html !== 'string' || !/<h[2-6][\\s>]/i.test(html)) return html\n // Every id the content already uses is taken, so a generated one never\n // duplicates it.\n var used = {}\n var existingIds = new RegExp(BLOG_HEADING_ID_PATTERN.source, 'gi')\n var existing\n while ((existing = existingIds.exec(html)) !== null) {\n used[decodeHtmlEntities(existing[2] || existing[3] || '')] = true\n }\n\n return html.replace(/<h([2-6])(\\s[^>]*)?>([\\s\\S]*?)<\\/h\\1>/gi, function(match, level, rawAttrs, inner) {\n if (inner.indexOf(BLOG_HEADING_ANCHOR_CLASS) !== -1) return match\n var text = stripHtmlTags(inner)\n if (!text) return match\n var attrs = rawAttrs || ''\n var idMatch = attrs.match(BLOG_HEADING_ID_PATTERN)\n var id = idMatch ? decodeHtmlEntities(idMatch[2] || idMatch[3] || '') : ''\n if (!id) {\n id = blogHeadingSlug(text, used)\n attrs = ' id=\"' + escapeHeadingAttribute(id) + '\"' + attrs\n }\n return (\n '<h' + level + attrs + '>' + inner +\n '<a class=\"' + BLOG_HEADING_ANCHOR_CLASS + '\" href=\"#' + escapeHeadingAttribute(id) +\n '\" aria-hidden=\"true\" tabindex=\"-1\">#</a>' +\n '</h' + level + '>'\n )\n })\n}\n"); };
|
|
25
|
+
//# sourceMappingURL=heading-anchors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heading-anchors.js","sourceRoot":"","sources":["../../../src/transformations/heading-anchors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,IAAM,yBAAyB,GAAG,mBAAmB,CAAA;AAE5D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,IAAM,0BAA0B,GAAG,cAAc,OAAA,6CACrB,yBAAyB,64DA2D3D,EA5DuD,CA4DvD,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GeneratorOptions, UIDLEcommerceCategory } from '@teleporthq/teleport-types';
|
|
1
|
+
import type { GeneratorOptions, UIDLAuthentication, UIDLEcommerceCategory } from '@teleporthq/teleport-types';
|
|
2
2
|
import { type EcommerceProductTransformOptions } from './ecommerce-product';
|
|
3
3
|
import { type ContentLocalization, type LocalizedProjectOptions } from '../content-localization';
|
|
4
4
|
export type { EcommerceProductTransformOptions };
|
|
@@ -11,6 +11,14 @@ export type { EcommerceProductTransformOptions };
|
|
|
11
11
|
export interface EntityTransformOptions extends EcommerceProductTransformOptions {
|
|
12
12
|
/** Blog post-category taxonomy — see `blogSettings.categories`. */
|
|
13
13
|
blogCategories?: UIDLEcommerceCategory[];
|
|
14
|
+
/** Post content headings get ids and `#` links — see `blogSettings.headingAnchors`. */
|
|
15
|
+
blogHeadingAnchors?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* A post details fetch carries the post's approved comments — see
|
|
18
|
+
* `blogSettings.comments`. Off, the comments table is never queried: a blog
|
|
19
|
+
* without comments has no such table.
|
|
20
|
+
*/
|
|
21
|
+
blogComments?: boolean;
|
|
14
22
|
/**
|
|
15
23
|
* The languages the rows are stored in — absent for a single-language
|
|
16
24
|
* project. The transform resolves every translatable field against the
|
|
@@ -18,6 +26,12 @@ export interface EntityTransformOptions extends EcommerceProductTransformOptions
|
|
|
18
26
|
* the fetcher matches and sorts translatable columns the same way.
|
|
19
27
|
*/
|
|
20
28
|
localization?: ContentLocalization;
|
|
29
|
+
/**
|
|
30
|
+
* Who may read a money table (gift cards, vouchers, their ledgers) from a
|
|
31
|
+
* browser: the roles the generated admin panel admits. See
|
|
32
|
+
* `TableAccess.resolveTrustedReaderRoles`.
|
|
33
|
+
*/
|
|
34
|
+
trustedReaderRoles?: string[];
|
|
21
35
|
}
|
|
22
36
|
/**
|
|
23
37
|
* Collects everything the product transform bakes in from the generator
|
|
@@ -28,7 +42,18 @@ export interface EntityTransformOptions extends EcommerceProductTransformOptions
|
|
|
28
42
|
* tax-inclusive or untaxed stores. `allowBackorders` is the effective
|
|
29
43
|
* "stock never blocks a purchase" flag — see `resolveAllowBackorders`.
|
|
30
44
|
*/
|
|
31
|
-
export declare const buildProductTransformOptions: (options: Pick<GeneratorOptions, 'ecommerceSettings' | 'invoiceSettings' | 'blogSettings'> & LocalizedProjectOptions
|
|
45
|
+
export declare const buildProductTransformOptions: (options: Pick<GeneratorOptions, 'ecommerceSettings' | 'invoiceSettings' | 'blogSettings' | 'auth'> & LocalizedProjectOptions & {
|
|
46
|
+
/**
|
|
47
|
+
* The SAME project authentication under the name a `ProjectUIDL` gives
|
|
48
|
+
* it — the project plugins call this with the UIDL itself, where the
|
|
49
|
+
* field is `authentication`, while a component plugin calls it with
|
|
50
|
+
* `GeneratorOptions`, where it is `auth`. Reading only one of the two
|
|
51
|
+
* left every fetcher emitted by the project plugins with an empty
|
|
52
|
+
* trusted-reader list, i.e. a generated admin panel refused its own
|
|
53
|
+
* money tables.
|
|
54
|
+
*/
|
|
55
|
+
authentication?: UIDLAuthentication;
|
|
56
|
+
}) => EntityTransformOptions;
|
|
32
57
|
export type TransformationType = 'blog-post' | 'ecommerce-product' | 'custom-page' | null;
|
|
33
58
|
/**
|
|
34
59
|
* Detects which transformation type to apply based on the table name.
|
|
@@ -49,11 +74,29 @@ export declare const detectTransformationType: (tableName: string) => Transforma
|
|
|
49
74
|
* Returns empty string if no transformation is needed for this table.
|
|
50
75
|
*/
|
|
51
76
|
export declare const getTransformationCode: (tableName: string, options?: EntityTransformOptions) => string;
|
|
77
|
+
/**
|
|
78
|
+
* The request parameter that asks a transformed table for its rows AS STORED.
|
|
79
|
+
*
|
|
80
|
+
* The product, blog-post and custom-page transforms build a storefront view
|
|
81
|
+
* model: camelCased keys, flags as `"true"`/`"false"` strings, derived fields,
|
|
82
|
+
* and several columns left out altogether (a product's `discounts`,
|
|
83
|
+
* `category_ids`, `download_limit`, …). A caller that WRITES the row back —
|
|
84
|
+
* the generated admin's edit forms — needs the columns themselves: fed the view
|
|
85
|
+
* model, its form showed a digital product as not digital, a gift card switch
|
|
86
|
+
* ticked on a product that is not one, no discounts, and every save wrote the
|
|
87
|
+
* missing columns back blank.
|
|
88
|
+
*
|
|
89
|
+
* ⛔ PAIRED with `ADMIN_RAW_ROWS_PARAM` in the GUI's
|
|
90
|
+
* `mappers/domain-to-uidl/feature-detail-page-options.ts`, which bakes it into
|
|
91
|
+
* the admin update pages' detail resource.
|
|
92
|
+
*/
|
|
93
|
+
export declare const RAW_ROWS_PARAM = "rawRows";
|
|
52
94
|
/**
|
|
53
95
|
* Returns the JavaScript expression that transforms the data array.
|
|
54
96
|
* This expression assumes the data array variable is called `safeData`,
|
|
55
97
|
* that `getClient` is available for asset resolution, and that `req` is in scope.
|
|
56
|
-
* Returns null if no transformation is needed.
|
|
98
|
+
* Returns null if no transformation is needed. A request carrying
|
|
99
|
+
* `RAW_ROWS_PARAM` gets the stored rows instead (see `rawRecords`).
|
|
57
100
|
*/
|
|
58
101
|
export declare const getTransformExpression: (tableName: string) => string | null;
|
|
59
102
|
/**
|
|
@@ -76,5 +119,5 @@ export declare const REVIEWS_PER_PRODUCT = 5;
|
|
|
76
119
|
* asked of every caller. Without a localization every row reads as before —
|
|
77
120
|
* the base columns.
|
|
78
121
|
*/
|
|
79
|
-
export declare const getTransformWrapperCode: (tableName: string, options?: Pick<EntityTransformOptions, 'localization'>) => string;
|
|
122
|
+
export declare const getTransformWrapperCode: (tableName: string, options?: Pick<EntityTransformOptions, 'localization' | 'blogComments'>) => string;
|
|
80
123
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transformations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transformations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,4BAA4B,CAAA;AAKnC,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC7B,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EAAE,gCAAgC,EAAE,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,sBAAuB,SAAQ,gCAAgC;IAC9E,mEAAmE;IACnE,cAAc,CAAC,EAAE,qBAAqB,EAAE,CAAA;IACxC,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAA;IAClC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B;AAkBD;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,YAC9B,KACP,gBAAgB,EAChB,mBAAmB,GAAG,iBAAiB,GAAG,cAAc,GAAG,MAAM,CAClE,GACC,uBAAuB,GAAG;IACxB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAA;CACpC,KACF,sBAUD,CAAA;AAEF,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,mBAAmB,GAAG,aAAa,GAAG,IAAI,CAAA;AAezF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,cAAe,MAAM,KAAG,kBAe5D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,cACrB,MAAM,YACR,sBAAsB,KAC9B,MAwBF,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,YAAY,CAAA;AAEvC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,cAAe,MAAM,KAAG,MAAM,GAAG,IAKnE,CAAA;AA+DD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAA;AAEpC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,cACvB,MAAM,YACR,KAAK,sBAAsB,EAAE,cAAc,GAAG,cAAc,CAAC,KACrE,MAkKF,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StorefrontTax } from '@teleporthq/teleport-shared';
|
|
1
|
+
import { StorefrontTax, TableAccess } from '@teleporthq/teleport-shared';
|
|
2
2
|
import { generateSharedTransformationCode } from './shared-utils';
|
|
3
3
|
import { generateBlogPostTransformationCode } from './blog-post';
|
|
4
4
|
import { generateCustomPageTransformationCode } from './custom-page';
|
|
@@ -29,13 +29,17 @@ var resolveAllowBackorders = function (settings) {
|
|
|
29
29
|
* "stock never blocks a purchase" flag — see `resolveAllowBackorders`.
|
|
30
30
|
*/
|
|
31
31
|
export var buildProductTransformOptions = function (options) {
|
|
32
|
-
var _a, _b;
|
|
32
|
+
var _a, _b, _c, _d, _e;
|
|
33
33
|
return ({
|
|
34
34
|
categories: (_a = options.ecommerceSettings) === null || _a === void 0 ? void 0 : _a.categories,
|
|
35
35
|
blogCategories: (_b = options.blogSettings) === null || _b === void 0 ? void 0 : _b.categories,
|
|
36
|
+
blogHeadingAnchors: ((_c = options.blogSettings) === null || _c === void 0 ? void 0 : _c.headingAnchors) === true,
|
|
37
|
+
blogComments: ((_d = options.blogSettings) === null || _d === void 0 ? void 0 : _d.comments) === true,
|
|
36
38
|
storefrontTaxRate: StorefrontTax.resolveStorefrontTaxRate(options.invoiceSettings),
|
|
37
39
|
allowBackorders: resolveAllowBackorders(options.ecommerceSettings),
|
|
40
|
+
productPages: (_e = options.ecommerceSettings) === null || _e === void 0 ? void 0 : _e.productPages,
|
|
38
41
|
localization: resolveContentLocalization(options),
|
|
42
|
+
trustedReaderRoles: TableAccess.resolveTrustedReaderRoles(options.auth || options.authentication),
|
|
39
43
|
});
|
|
40
44
|
};
|
|
41
45
|
/**
|
|
@@ -92,7 +96,11 @@ export var getTransformationCode = function (tableName, options) {
|
|
|
92
96
|
var shared = generateSharedTransformationCode();
|
|
93
97
|
switch (type) {
|
|
94
98
|
case 'blog-post':
|
|
95
|
-
return shared +
|
|
99
|
+
return (shared +
|
|
100
|
+
generateBlogPostTransformationCode({
|
|
101
|
+
categories: options.blogCategories,
|
|
102
|
+
headingAnchors: options.blogHeadingAnchors,
|
|
103
|
+
}));
|
|
96
104
|
case 'ecommerce-product':
|
|
97
105
|
return shared + generateEcommerceProductTransformationCode(options);
|
|
98
106
|
case 'custom-page':
|
|
@@ -101,28 +109,45 @@ export var getTransformationCode = function (tableName, options) {
|
|
|
101
109
|
return '';
|
|
102
110
|
}
|
|
103
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* The request parameter that asks a transformed table for its rows AS STORED.
|
|
114
|
+
*
|
|
115
|
+
* The product, blog-post and custom-page transforms build a storefront view
|
|
116
|
+
* model: camelCased keys, flags as `"true"`/`"false"` strings, derived fields,
|
|
117
|
+
* and several columns left out altogether (a product's `discounts`,
|
|
118
|
+
* `category_ids`, `download_limit`, …). A caller that WRITES the row back —
|
|
119
|
+
* the generated admin's edit forms — needs the columns themselves: fed the view
|
|
120
|
+
* model, its form showed a digital product as not digital, a gift card switch
|
|
121
|
+
* ticked on a product that is not one, no discounts, and every save wrote the
|
|
122
|
+
* missing columns back blank.
|
|
123
|
+
*
|
|
124
|
+
* ⛔ PAIRED with `ADMIN_RAW_ROWS_PARAM` in the GUI's
|
|
125
|
+
* `mappers/domain-to-uidl/feature-detail-page-options.ts`, which bakes it into
|
|
126
|
+
* the admin update pages' detail resource.
|
|
127
|
+
*/
|
|
128
|
+
export var RAW_ROWS_PARAM = 'rawRows';
|
|
104
129
|
/**
|
|
105
130
|
* Returns the JavaScript expression that transforms the data array.
|
|
106
131
|
* This expression assumes the data array variable is called `safeData`,
|
|
107
132
|
* that `getClient` is available for asset resolution, and that `req` is in scope.
|
|
108
|
-
* Returns null if no transformation is needed.
|
|
133
|
+
* Returns null if no transformation is needed. A request carrying
|
|
134
|
+
* `RAW_ROWS_PARAM` gets the stored rows instead (see `rawRecords`).
|
|
109
135
|
*/
|
|
110
136
|
export var getTransformExpression = function (tableName) {
|
|
111
|
-
|
|
112
|
-
if (!type) {
|
|
137
|
+
if (!detectTransformationType(tableName)) {
|
|
113
138
|
return null;
|
|
114
139
|
}
|
|
115
|
-
|
|
116
|
-
case 'blog-post':
|
|
117
|
-
return 'await transformRecords(safeData, getClient, req.query)';
|
|
118
|
-
case 'ecommerce-product':
|
|
119
|
-
return 'await transformRecords(safeData, getClient, req.query)';
|
|
120
|
-
case 'custom-page':
|
|
121
|
-
return 'await transformRecords(safeData, getClient, req.query)';
|
|
122
|
-
default:
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
140
|
+
return '(__tqWantsRawRows(req.query) ? await rawRecords(safeData, getClient) : await transformRecords(safeData, getClient, req.query))';
|
|
125
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* The raw-rows mode every transformed table's fetcher carries: the rows as
|
|
144
|
+
* stored, with one exception — a value that is an uploaded asset's ID, alone or
|
|
145
|
+
* inside a JSON list column, becomes the URL the transform would have shown, so
|
|
146
|
+
* an edit form's image previews keep working. Nothing else is renamed, derived
|
|
147
|
+
* or dropped. The response cache keys on the query, so the two modes never
|
|
148
|
+
* share an entry.
|
|
149
|
+
*/
|
|
150
|
+
var RAW_ROWS_CODE = "\nfunction __tqWantsRawRows(query) {\n var flag = query ? query.".concat(RAW_ROWS_PARAM, " : undefined\n return flag === true || flag === 'true'\n}\n\nasync function rawRecords(records, getClientFn) {\n if (!Array.isArray(records)) return []\n var assetMap = {}\n try {\n assetMap = await getAssetMap(getClientFn)\n } catch (e) {\n // Asset resolution is best-effort; the stored values pass through as they are.\n }\n return records.map(function(record) { return __tqResolveRowAssets(record, assetMap || {}) })\n}\n\nfunction __tqResolveRowAssets(record, assetMap) {\n if (!record || typeof record !== 'object' || Array.isArray(record)) return record\n var out = {}\n for (var key in record) {\n if (!Object.prototype.hasOwnProperty.call(record, key)) continue\n out[key] = __tqResolveAssetValue(record[key], assetMap)\n }\n return out\n}\n\nfunction __tqIsAssetId(value, assetMap) {\n return typeof value === 'string' && value !== '' && Object.prototype.hasOwnProperty.call(assetMap, value)\n}\n\nfunction __tqResolveAssetValue(value, assetMap) {\n if (typeof value !== 'string' || !value) return value\n if (__tqIsAssetId(value, assetMap)) return resolveAssetUrl(value, assetMap)\n var trimmed = value.trim()\n if (trimmed.charAt(0) !== '[') return value\n var list\n try {\n list = JSON.parse(trimmed)\n } catch (e) {\n return value\n }\n if (!Array.isArray(list)) return value\n var changed = false\n var resolved = list.map(function(item) {\n if (!__tqIsAssetId(item, assetMap)) return item\n changed = true\n return resolveAssetUrl(item, assetMap)\n })\n return changed ? JSON.stringify(resolved) : value\n}\n");
|
|
126
151
|
/**
|
|
127
152
|
* How many reviews a product page carries into its structured data.
|
|
128
153
|
*
|
|
@@ -171,8 +196,10 @@ export var getTransformWrapperCode = function (tableName, options) {
|
|
|
171
196
|
var variantEnrichment = type === 'ecommerce-product'
|
|
172
197
|
? "\n var variantsByProductId = null\n // Declared OUTSIDE the try because the ratings lookup below reuses it. `var`\n // would hoist it anyway, but relying on that would make this block break\n // silently the day someone modernises it to `let`.\n var __variantPids = []\n try {\n for (var __i = 0; __i < records.length; __i++) {\n if (records[__i] && records[__i].id != null) __variantPids.push(records[__i].id)\n }\n if (relatedProductsById) {\n for (var __rk in relatedProductsById) {\n if (!Object.prototype.hasOwnProperty.call(relatedProductsById, __rk)) continue\n // The ROW's own id, not the map key: the key was stringified when the map\n // was built, and a query parameter array of mixed types is one the driver\n // cannot type against the product_id column.\n var __rrow = relatedProductsById[__rk]\n if (__rrow && __rrow.id != null) __variantPids.push(__rrow.id)\n }\n }\n variantsByProductId = await getVariantsMap(getClientFn, __variantPids)\n } catch (e) {\n // Leaves the map null \u2014 \"unknown\", never \"none\".\n }\n // The aggregate star rating for the same id set, in ONE more query. Reuses\n // __variantPids so a details page's related cards get their ratings from the\n // same round trip rather than one query per card.\n //\n // Unlike the variants map this stays {} on failure: \"no rating to show\" is\n // both the empty answer and the safe answer, so there is no unknown state for\n // a caller to reason about.\n var ratingsByProductId = {}\n try {\n ratingsByProductId = await getRatingsMap(getClientFn, __variantPids)\n } catch (e) {\n // Leaves the map empty \u2014 the star rows simply stay hidden.\n }\n // The individual reviews behind the stars, for the product page's JSON-LD.\n //\n // Gated on the SINGLE-RECORD heuristic, unlike the two lookups above. Those\n // feed something every card on the page draws; this feeds structured data,\n // which only a details page emits \u2014 and a listing of 24 products would\n // otherwise fetch and inline 120 review rows that nothing on it renders or\n // markup-references.\n var reviewsByProductId = {}\n if (Array.isArray(records) && records.length === 1) {\n try {\n reviewsByProductId = await getProductReviewsMap(getClientFn, __variantPids, ".concat(REVIEWS_PER_PRODUCT, ")\n } catch (e) {\n // Best-effort; the product simply ships without review snippets.\n }\n }")
|
|
173
198
|
: '';
|
|
199
|
+
// `includeOptionDetail` uses the same single-record heuristic as the related
|
|
200
|
+
// items: only the details page carries a product's full option tree.
|
|
174
201
|
var variantOption = type === 'ecommerce-product'
|
|
175
|
-
? ', variantsByProductId: variantsByProductId, ratingsByProductId: ratingsByProductId, reviewsByProductId: reviewsByProductId'
|
|
202
|
+
? ', variantsByProductId: variantsByProductId, ratingsByProductId: ratingsByProductId, reviewsByProductId: reviewsByProductId, includeOptionDetail: Array.isArray(records) && records.length === 1'
|
|
176
203
|
: '';
|
|
177
204
|
// Related items are resolved for a SINGLE-record fetch only — which is the
|
|
178
205
|
// details page, the one surface that renders them (it looks the row up by
|
|
@@ -194,6 +221,17 @@ export var getTransformWrapperCode = function (tableName, options) {
|
|
|
194
221
|
? "\n var ".concat(relatedMapVar, " = null\n if (Array.isArray(records) && records.length === 1) {\n try {\n ").concat(relatedMapVar, " = await ").concat(relatedMapFn, "(getClientFn, records)\n } catch (e) {\n // Best-effort; the related rail stays hidden behind its empty gate.\n }\n }")
|
|
195
222
|
: '';
|
|
196
223
|
var relatedOption = hasRelatedItems ? ", ".concat(relatedMapVar, ": ").concat(relatedMapVar) : '';
|
|
197
|
-
|
|
224
|
+
// A post page's neighbours and comments, on the same single-record heuristic
|
|
225
|
+
// as the related rail. The comments are only asked for when the blog takes
|
|
226
|
+
// them — see `EntityTransformOptions.blogComments`.
|
|
227
|
+
var blogPageEnrichment = type === 'blog-post'
|
|
228
|
+
? "\n var adjacentPostsById = null\n var commentsByPostId = null\n if (Array.isArray(records) && records.length === 1) {\n try {\n adjacentPostsById = await getAdjacentPostsMap(getClientFn, records)\n } catch (e) {\n // Best-effort; the post navigation stays hidden.\n }".concat(options.blogComments
|
|
229
|
+
? "\n try {\n commentsByPostId = await getBlogCommentsMap(getClientFn, records)\n } catch (e) {\n // Best-effort; the post renders without comments.\n }"
|
|
230
|
+
: '', "\n }")
|
|
231
|
+
: '';
|
|
232
|
+
var blogPageOption = type === 'blog-post'
|
|
233
|
+
? ', adjacentPostsById: adjacentPostsById, commentsByPostId: commentsByPostId'
|
|
234
|
+
: '';
|
|
235
|
+
return "".concat(RAW_ROWS_CODE, "\nasync function transformRecords(records, getClientFn, reqQuery) {\n var assetMap = {}\n try {\n assetMap = await getAssetMap(getClientFn)\n } catch (e) {\n // Asset resolution is best-effort; continue without it\n }").concat(relatedEnrichment).concat(blogPageEnrichment).concat(variantEnrichment, "\n var currentLanguage = reqQuery && typeof reqQuery.").concat(REQUEST_LOCALE_PARAM, " === 'string' && reqQuery.").concat(REQUEST_LOCALE_PARAM, " ? reqQuery.").concat(REQUEST_LOCALE_PARAM, " : null\n var options = { assetMap: assetMap, currentLanguage: currentLanguage, mainLanguage: ").concat(mainLanguageLiteral).concat(variantOption).concat(relatedOption).concat(blogPageOption, " }\n return ").concat(transformFn, "(records, options)\n}\n");
|
|
198
236
|
};
|
|
199
237
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transformations/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transformations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-utils.d.ts","sourceRoot":"","sources":["../../../src/transformations/shared-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,QAAO,
|
|
1
|
+
{"version":3,"file":"shared-utils.d.ts","sourceRoot":"","sources":["../../../src/transformations/shared-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,QAAO,MA0TnD,CAAA"}
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* when the table requires blog post or e-commerce product transformations.
|
|
5
5
|
*/
|
|
6
6
|
export var generateSharedTransformationCode = function () {
|
|
7
|
-
return "\n// ============================================================\n// Shared Data Transformation Utilities\n// ============================================================\n\nvar CURRENCY_SYMBOLS = {\n USD: { symbol: '$', position: 'before' },\n EUR: { symbol: '\u20AC', position: 'before' },\n GBP: { symbol: '\u00A3', position: 'before' },\n JPY: { symbol: '\u00A5', position: 'before' },\n CAD: { symbol: 'C$', position: 'before' },\n AUD: { symbol: 'A$', position: 'before' },\n CHF: { symbol: 'CHF', position: 'before' },\n CNY: { symbol: '\u00A5', position: 'before' },\n INR: { symbol: '\u20B9', position: 'before' },\n BRL: { symbol: 'R$', position: 'before' },\n MXN: { symbol: 'MX$', position: 'before' },\n KRW: { symbol: '\u20A9', position: 'before' },\n SGD: { symbol: 'S$', position: 'before' },\n HKD: { symbol: 'HK$', position: 'before' },\n NOK: { symbol: 'kr', position: 'after' },\n SEK: { symbol: 'kr', position: 'after' },\n DKK: { symbol: 'kr', position: 'after' },\n PLN: { symbol: 'z\u0142', position: 'after' },\n CZK: { symbol: 'K\u010D', position: 'after' },\n HUF: { symbol: 'Ft', position: 'after' },\n RON: { symbol: 'lei', position: 'after' },\n TRY: { symbol: '\u20BA', position: 'before' },\n THB: { symbol: '\u0E3F', position: 'before' },\n IDR: { symbol: 'Rp', position: 'before' },\n PHP: { symbol: '\u20B1', position: 'before' },\n ZAR: { symbol: 'R', position: 'before' },\n RUB: { symbol: '\u20BD', position: 'after' },\n NZD: { symbol: 'NZ$', position: 'before' },\n TWD: { symbol: 'NT$', position: 'before' },\n ILS: { symbol: '\u20AA', position: 'before' },\n AED: { symbol: '\u062F.\u0625', position: 'before' },\n SAR: { symbol: '\uFDFC', position: 'before' },\n MYR: { symbol: 'RM', position: 'before' },\n VND: { symbol: '\u20AB', position: 'after' },\n CLP: { symbol: '$', position: 'before' },\n COP: { symbol: '$', position: 'before' },\n ARS: { symbol: '$', position: 'before' },\n PEN: { symbol: 'S/', position: 'before' },\n UAH: { symbol: '\u20B4', position: 'after' },\n BGN: { symbol: '\u043B\u0432', position: 'after' },\n HRK: { symbol: 'kn', position: 'after' },\n ISK: { symbol: 'kr', position: 'after' },\n NGN: { symbol: '\u20A6', position: 'before' },\n KES: { symbol: 'KSh', position: 'before' },\n EGP: { symbol: 'E\u00A3', position: 'before' },\n PKR: { symbol: '\u20A8', position: 'before' },\n BDT: { symbol: '\u09F3', position: 'before' },\n LKR: { symbol: '\u20A8', position: 'before' },\n GHS: { symbol: 'GH\u20B5', position: 'before' },\n}\n\nfunction getCurrencyInfo(currencyCode) {\n if (!currencyCode) return { symbol: '$', position: 'before' }\n var upper = currencyCode.toUpperCase()\n var entry = CURRENCY_SYMBOLS[upper]\n return entry || { symbol: upper, position: 'before' }\n}\n\nfunction getCurrencySymbol(currencyCode) {\n return getCurrencyInfo(currencyCode).symbol\n}\n\nfunction normalizeTimestamp(value) {\n if (value == null) return Date.now()\n if (typeof value === 'number') {\n if (isNaN(value)) return Date.now()\n return value < 100000000000 ? value * 1000 : value\n }\n if (typeof value === 'string') {\n var parsed = Date.parse(value)\n return isNaN(parsed) ? Date.now() : parsed\n }\n return Date.now()\n}\n\nfunction safeNumber(value, defaultValue) {\n if (value == null) return defaultValue\n var n = Number(value)\n return isNaN(n) ? defaultValue : n\n}\n\nfunction parseJsonArray(value) {\n if (!value) return []\n if (Array.isArray(value)) return value.filter(function(item) { return typeof item === 'string' })\n if (typeof value === 'string') {\n try {\n var parsed = JSON.parse(value)\n if (Array.isArray(parsed)) return parsed.filter(function(item) { return typeof item === 'string' })\n return []\n } catch (e) {\n return value.split(',').map(function(s) { return s.trim() }).filter(Boolean)\n }\n }\n return []\n}\n\n// The related-item picks a merchant/author made: a JSON array of row ids stored\n// in a TEXT column (`related_product_ids` / `related_post_ids`). Mirrors\n// parseRelatedEntityIds in the GUI (apps/gui/app/project-page/features/shared/\n// related-entities/related-entity-ids.ts) \u2014 order-preserving, deduplicated,\n// blanks dropped, tolerant of a comma-separated cell edited by hand.\n//\n// `indexOf` rather than a seen-map on purpose: these lists hold a handful of\n// entries, and an object keyed by arbitrary strings answers truthy for\n// 'constructor'/'toString'.\nfunction parseRelatedIds(value) {\n var raw = parseJsonArray(value)\n var ids = []\n for (var i = 0; i < raw.length; i++) {\n var id = String(raw[i] == null ? '' : raw[i]).trim()\n if (!id || ids.indexOf(id) !== -1) continue\n ids.push(id)\n }\n return ids\n}\n\nfunction parseJsonObject(value) {\n if (value == null) return {}\n if (typeof value === 'object' && !Array.isArray(value)) return value\n if (typeof value === 'string') {\n try {\n var parsed = JSON.parse(value)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return parsed\n return {}\n } catch (e) {\n return {}\n }\n }\n return {}\n}\n\nvar HTML_ENTITY_MAP = {\n '&': '&', '<': '<', '>': '>', '"': '\"',\n ''': \"'\", ''': \"'\", ''': \"'\", ' ': ' ',\n ' ': ' ', '©': '\u00A9', '®': '\u00AE', '™': '\u2122',\n '…': '\u2026', '—': '\u2014', '–': '\u2013',\n}\n\nfunction decodeHtmlEntities(str) {\n if (!str) return str\n // Decode named and numeric entities\n return str\n .replace(/&(?:#x([0-9a-fA-F]+)|#([0-9]+)|([a-zA-Z]+));/g, function(match, hex, dec, named) {\n if (hex) return String.fromCharCode(parseInt(hex, 16))\n if (dec) return String.fromCharCode(parseInt(dec, 10))\n var namedRef = '&' + named + ';'\n return HTML_ENTITY_MAP[namedRef] || match\n })\n}\n\nfunction stripHtmlTags(html) {\n if (!html || typeof html !== 'string') return ''\n // Remove script and style blocks entirely (including content)\n var cleaned = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n // Strip remaining tags\n cleaned = cleaned.replace(/<[^>]*>/g, ' ')\n // Decode HTML entities\n cleaned = decodeHtmlEntities(cleaned)\n // Collapse whitespace\n return cleaned.replace(/\\s+/g, ' ').trim()\n}\n\nfunction coerceBoolean(value, defaultValue) {\n if (value === true || value === 'true' || value === 1 || value === '1') return true\n if (value === false || value === 'false' || value === 0 || value === '0') return false\n return defaultValue\n}\n\nfunction pickFirst() {\n for (var i = 0; i < arguments.length; i++) {\n var val = arguments[i]\n if (val !== undefined && val !== null) return val\n }\n return null\n}\n\nfunction resolveI18nField(record, snakeCol, camelCol, currentLang, mainLang) {\n if (currentLang && mainLang && currentLang !== mainLang) {\n // Try language-prefixed snake_case column first, then camelCase\n var langSnakeKey = currentLang + '_' + snakeCol\n if (record[langSnakeKey] !== undefined && record[langSnakeKey] !== null && record[langSnakeKey] !== '') {\n return record[langSnakeKey]\n }\n if (snakeCol !== camelCol) {\n var langCamelKey = currentLang + '_' + camelCol\n if (record[langCamelKey] !== undefined && record[langCamelKey] !== null && record[langCamelKey] !== '') {\n return record[langCamelKey]\n }\n }\n }\n if (record[snakeCol] !== undefined && record[snakeCol] !== null) return record[snakeCol]\n if (snakeCol !== camelCol && record[camelCol] !== undefined && record[camelCol] !== null) return record[camelCol]\n return null\n}\n\n// Asset URL Resolution with TTL-based caching\nvar __assetUrlCache = {}\nvar __assetMapCache = null\nvar __assetMapTimestamp = 0\nvar ASSET_CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes\n\nfunction isUrl(value) {\n if (!value || typeof value !== 'string') return false\n return value.startsWith('http://') || value.startsWith('https://') || value.startsWith('data:')\n}\n\nfunction resolveAssetUrl(value, assetMap) {\n if (!value || typeof value !== 'string') return null\n if (isUrl(value)) return value\n // Also treat absolute paths (starting with /) as URLs\n if (value.charAt(0) === '/') return value\n if (__assetUrlCache[value]) return __assetUrlCache[value]\n if (assetMap && assetMap[value]) {\n var asset = assetMap[value]\n var resolved = asset.remoteSrc || asset.imageSrc || asset.src || asset.url || value\n __assetUrlCache[value] = resolved\n return resolved\n }\n // Not found in asset map - return as-is (might already be a usable reference)\n return value\n}\n\n// Whether an asset-id resolution produced a real URL. resolveAssetUrl returns\n// an UNKNOWN id verbatim (asset deleted, teleport_assets not mirrored yet) and\n// a bare 'TQ_...' must never reach a <model-viewer src> or a poster.\nfunction isResolvedMediaUrl(value) {\n return typeof value === 'string' && (isUrl(value) || value.charAt(0) === '/')\n}\n\n// resolveAssetUrl for MEDIA that has no safe fallback: a value that did not\n// resolve to a URL is reported as absent (null) instead of passed through.\nfunction resolveMediaUrl(value, assetMap) {\n var resolved = resolveAssetUrl(value, assetMap)\n return isResolvedMediaUrl(resolved) ? resolved : null\n}\n\n// Trims a per-row SEO URL cell (blog posts, custom pages); blank/non-string\n// values \u2014 including columns that don't exist yet on tables provisioned before\n// the feature \u2014 become null.\nfunction normalizeSeoUrlField(value) {\n if (typeof value !== 'string') return null\n var trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction resolveAssetUrls(values, assetMap) {\n if (!Array.isArray(values)) return []\n return values\n .map(function(v) { return resolveAssetUrl(v, assetMap) })\n .filter(function(v) { return v != null && typeof v === 'string' })\n}\n\nfunction deduplicateStrings(arr) {\n var seen = {}\n return arr.filter(function(v) {\n if (!v || typeof v !== 'string' || seen[v]) return false\n seen[v] = true\n return true\n })\n}\n\n// Fetches the asset map from the database if available, with TTL-based caching\nasync function getAssetMap(getClientFn) {\n var now = Date.now()\n if (__assetMapCache && (now - __assetMapTimestamp) < ASSET_CACHE_TTL_MS) {\n return __assetMapCache\n }\n // Reset per-URL cache when asset map is refreshed\n __assetUrlCache = {}\n var map = {}\n var client\n try {\n client = getClientFn()\n await client.connect()\n var result = await client.query('SELECT id, src, remote_src, image_src, url FROM teleport_assets')\n if (result && result.rows) {\n result.rows.forEach(function(row) {\n map[row.id] = {\n src: row.src || null,\n remoteSrc: row.remote_src || null,\n imageSrc: row.image_src || null,\n url: row.url || null,\n }\n })\n }\n __assetMapCache = map\n __assetMapTimestamp = now\n } catch (e) {\n // teleport_assets table may not exist - cache empty map with short TTL\n __assetMapCache = map\n __assetMapTimestamp = now\n } finally {\n if (client) {\n try { await client.end() } catch (e) { /* ignore */ }\n }\n }\n return map\n}\n";
|
|
7
|
+
return "\n// ============================================================\n// Shared Data Transformation Utilities\n// ============================================================\n\nvar CURRENCY_SYMBOLS = {\n USD: { symbol: '$', position: 'before' },\n EUR: { symbol: '\u20AC', position: 'before' },\n GBP: { symbol: '\u00A3', position: 'before' },\n JPY: { symbol: '\u00A5', position: 'before' },\n CAD: { symbol: 'C$', position: 'before' },\n AUD: { symbol: 'A$', position: 'before' },\n CHF: { symbol: 'CHF', position: 'before' },\n CNY: { symbol: '\u00A5', position: 'before' },\n INR: { symbol: '\u20B9', position: 'before' },\n BRL: { symbol: 'R$', position: 'before' },\n MXN: { symbol: 'MX$', position: 'before' },\n KRW: { symbol: '\u20A9', position: 'before' },\n SGD: { symbol: 'S$', position: 'before' },\n HKD: { symbol: 'HK$', position: 'before' },\n NOK: { symbol: 'kr', position: 'after' },\n SEK: { symbol: 'kr', position: 'after' },\n DKK: { symbol: 'kr', position: 'after' },\n PLN: { symbol: 'z\u0142', position: 'after' },\n CZK: { symbol: 'K\u010D', position: 'after' },\n HUF: { symbol: 'Ft', position: 'after' },\n RON: { symbol: 'lei', position: 'after' },\n TRY: { symbol: '\u20BA', position: 'before' },\n THB: { symbol: '\u0E3F', position: 'before' },\n IDR: { symbol: 'Rp', position: 'before' },\n PHP: { symbol: '\u20B1', position: 'before' },\n ZAR: { symbol: 'R', position: 'before' },\n RUB: { symbol: '\u20BD', position: 'after' },\n NZD: { symbol: 'NZ$', position: 'before' },\n TWD: { symbol: 'NT$', position: 'before' },\n ILS: { symbol: '\u20AA', position: 'before' },\n AED: { symbol: '\u062F.\u0625', position: 'before' },\n SAR: { symbol: '\uFDFC', position: 'before' },\n MYR: { symbol: 'RM', position: 'before' },\n VND: { symbol: '\u20AB', position: 'after' },\n CLP: { symbol: '$', position: 'before' },\n COP: { symbol: '$', position: 'before' },\n ARS: { symbol: '$', position: 'before' },\n PEN: { symbol: 'S/', position: 'before' },\n UAH: { symbol: '\u20B4', position: 'after' },\n BGN: { symbol: '\u043B\u0432', position: 'after' },\n HRK: { symbol: 'kn', position: 'after' },\n ISK: { symbol: 'kr', position: 'after' },\n NGN: { symbol: '\u20A6', position: 'before' },\n KES: { symbol: 'KSh', position: 'before' },\n EGP: { symbol: 'E\u00A3', position: 'before' },\n PKR: { symbol: '\u20A8', position: 'before' },\n BDT: { symbol: '\u09F3', position: 'before' },\n LKR: { symbol: '\u20A8', position: 'before' },\n GHS: { symbol: 'GH\u20B5', position: 'before' },\n}\n\nfunction getCurrencyInfo(currencyCode) {\n if (!currencyCode) return { symbol: '$', position: 'before' }\n var upper = currencyCode.toUpperCase()\n var entry = CURRENCY_SYMBOLS[upper]\n return entry || { symbol: upper, position: 'before' }\n}\n\nfunction getCurrencySymbol(currencyCode) {\n return getCurrencyInfo(currencyCode).symbol\n}\n\nfunction normalizeTimestamp(value) {\n if (value == null) return Date.now()\n // A row read straight off the driver (the related / adjacent lookups) carries\n // its timestamps as Date objects.\n if (value instanceof Date) {\n var time = value.getTime()\n return isNaN(time) ? Date.now() : time\n }\n if (typeof value === 'number') {\n if (isNaN(value)) return Date.now()\n return value < 100000000000 ? value * 1000 : value\n }\n if (typeof value === 'string') {\n var parsed = Date.parse(value)\n return isNaN(parsed) ? Date.now() : parsed\n }\n return Date.now()\n}\n\nfunction safeNumber(value, defaultValue) {\n if (value == null) return defaultValue\n var n = Number(value)\n return isNaN(n) ? defaultValue : n\n}\n\nfunction parseJsonArray(value) {\n if (!value) return []\n if (Array.isArray(value)) return value.filter(function(item) { return typeof item === 'string' })\n if (typeof value === 'string') {\n try {\n var parsed = JSON.parse(value)\n if (Array.isArray(parsed)) return parsed.filter(function(item) { return typeof item === 'string' })\n return []\n } catch (e) {\n return value.split(',').map(function(s) { return s.trim() }).filter(Boolean)\n }\n }\n return []\n}\n\n// The related-item picks a merchant/author made: a JSON array of row ids stored\n// in a TEXT column (`related_product_ids` / `related_post_ids`). Mirrors\n// parseRelatedEntityIds in the GUI (apps/gui/app/project-page/features/shared/\n// related-entities/related-entity-ids.ts) \u2014 order-preserving, deduplicated,\n// blanks dropped, tolerant of a comma-separated cell edited by hand.\n//\n// `indexOf` rather than a seen-map on purpose: these lists hold a handful of\n// entries, and an object keyed by arbitrary strings answers truthy for\n// 'constructor'/'toString'.\nfunction parseRelatedIds(value) {\n var raw = parseJsonArray(value)\n var ids = []\n for (var i = 0; i < raw.length; i++) {\n var id = String(raw[i] == null ? '' : raw[i]).trim()\n if (!id || ids.indexOf(id) !== -1) continue\n ids.push(id)\n }\n return ids\n}\n\nfunction parseJsonObject(value) {\n if (value == null) return {}\n if (typeof value === 'object' && !Array.isArray(value)) return value\n if (typeof value === 'string') {\n try {\n var parsed = JSON.parse(value)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return parsed\n return {}\n } catch (e) {\n return {}\n }\n }\n return {}\n}\n\nvar HTML_ENTITY_MAP = {\n '&': '&', '<': '<', '>': '>', '"': '\"',\n ''': \"'\", ''': \"'\", ''': \"'\", ' ': ' ',\n ' ': ' ', '©': '\u00A9', '®': '\u00AE', '™': '\u2122',\n '…': '\u2026', '—': '\u2014', '–': '\u2013',\n}\n\nfunction decodeHtmlEntities(str) {\n if (!str) return str\n // Decode named and numeric entities\n return str\n .replace(/&(?:#x([0-9a-fA-F]+)|#([0-9]+)|([a-zA-Z]+));/g, function(match, hex, dec, named) {\n if (hex) return String.fromCharCode(parseInt(hex, 16))\n if (dec) return String.fromCharCode(parseInt(dec, 10))\n var namedRef = '&' + named + ';'\n return HTML_ENTITY_MAP[namedRef] || match\n })\n}\n\nfunction stripHtmlTags(html) {\n if (!html || typeof html !== 'string') return ''\n // Remove script and style blocks entirely (including content)\n var cleaned = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n // Strip remaining tags\n cleaned = cleaned.replace(/<[^>]*>/g, ' ')\n // Decode HTML entities\n cleaned = decodeHtmlEntities(cleaned)\n // Collapse whitespace\n return cleaned.replace(/\\s+/g, ' ').trim()\n}\n\nfunction coerceBoolean(value, defaultValue) {\n if (value === true || value === 'true' || value === 1 || value === '1') return true\n if (value === false || value === 'false' || value === 0 || value === '0') return false\n return defaultValue\n}\n\nfunction pickFirst() {\n for (var i = 0; i < arguments.length; i++) {\n var val = arguments[i]\n if (val !== undefined && val !== null) return val\n }\n return null\n}\n\nfunction resolveI18nField(record, snakeCol, camelCol, currentLang, mainLang) {\n if (currentLang && mainLang && currentLang !== mainLang) {\n // Try language-prefixed snake_case column first, then camelCase\n var langSnakeKey = currentLang + '_' + snakeCol\n if (record[langSnakeKey] !== undefined && record[langSnakeKey] !== null && record[langSnakeKey] !== '') {\n return record[langSnakeKey]\n }\n if (snakeCol !== camelCol) {\n var langCamelKey = currentLang + '_' + camelCol\n if (record[langCamelKey] !== undefined && record[langCamelKey] !== null && record[langCamelKey] !== '') {\n return record[langCamelKey]\n }\n }\n }\n if (record[snakeCol] !== undefined && record[snakeCol] !== null) return record[snakeCol]\n if (snakeCol !== camelCol && record[camelCol] !== undefined && record[camelCol] !== null) return record[camelCol]\n return null\n}\n\n// Asset URL Resolution with TTL-based caching\nvar __assetUrlCache = {}\nvar __assetMapCache = null\nvar __assetMapTimestamp = 0\nvar ASSET_CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes\n\nfunction isUrl(value) {\n if (!value || typeof value !== 'string') return false\n return value.startsWith('http://') || value.startsWith('https://') || value.startsWith('data:')\n}\n\nfunction resolveAssetUrl(value, assetMap) {\n if (!value || typeof value !== 'string') return null\n if (isUrl(value)) return value\n // Also treat absolute paths (starting with /) as URLs\n if (value.charAt(0) === '/') return value\n if (__assetUrlCache[value]) return __assetUrlCache[value]\n if (assetMap && assetMap[value]) {\n var asset = assetMap[value]\n var resolved = asset.remoteSrc || asset.imageSrc || asset.src || asset.url || value\n __assetUrlCache[value] = resolved\n return resolved\n }\n // Not found in asset map - return as-is (might already be a usable reference)\n return value\n}\n\n// Whether an asset-id resolution produced a real URL. resolveAssetUrl returns\n// an UNKNOWN id verbatim (asset deleted, teleport_assets not mirrored yet) and\n// a bare 'TQ_...' must never reach a <model-viewer src> or a poster.\nfunction isResolvedMediaUrl(value) {\n return typeof value === 'string' && (isUrl(value) || value.charAt(0) === '/')\n}\n\n// resolveAssetUrl for MEDIA that has no safe fallback: a value that did not\n// resolve to a URL is reported as absent (null) instead of passed through.\nfunction resolveMediaUrl(value, assetMap) {\n var resolved = resolveAssetUrl(value, assetMap)\n return isResolvedMediaUrl(resolved) ? resolved : null\n}\n\n// Trims a per-row SEO URL cell (blog posts, custom pages); blank/non-string\n// values \u2014 including columns that don't exist yet on tables provisioned before\n// the feature \u2014 become null.\nfunction normalizeSeoUrlField(value) {\n if (typeof value !== 'string') return null\n var trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction resolveAssetUrls(values, assetMap) {\n if (!Array.isArray(values)) return []\n return values\n .map(function(v) { return resolveAssetUrl(v, assetMap) })\n .filter(function(v) { return v != null && typeof v === 'string' })\n}\n\nfunction deduplicateStrings(arr) {\n var seen = {}\n return arr.filter(function(v) {\n if (!v || typeof v !== 'string' || seen[v]) return false\n seen[v] = true\n return true\n })\n}\n\n// Fetches the asset map from the database if available, with TTL-based caching\nasync function getAssetMap(getClientFn) {\n var now = Date.now()\n if (__assetMapCache && (now - __assetMapTimestamp) < ASSET_CACHE_TTL_MS) {\n return __assetMapCache\n }\n // Reset per-URL cache when asset map is refreshed\n __assetUrlCache = {}\n var map = {}\n var client\n try {\n client = getClientFn()\n await client.connect()\n var result = await client.query('SELECT id, src, remote_src, image_src, url FROM teleport_assets')\n if (result && result.rows) {\n result.rows.forEach(function(row) {\n map[row.id] = {\n src: row.src || null,\n remoteSrc: row.remote_src || null,\n imageSrc: row.image_src || null,\n url: row.url || null,\n }\n })\n }\n __assetMapCache = map\n __assetMapTimestamp = now\n } catch (e) {\n // teleport_assets table may not exist - cache empty map with short TTL\n __assetMapCache = map\n __assetMapTimestamp = now\n } finally {\n if (client) {\n try { await client.end() } catch (e) { /* ignore */ }\n }\n }\n return map\n}\n";
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=shared-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-utils.js","sourceRoot":"","sources":["../../../src/transformations/shared-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,IAAM,gCAAgC,GAAG;IAC9C,OAAO,
|
|
1
|
+
{"version":3,"file":"shared-utils.js","sourceRoot":"","sources":["../../../src/transformations/shared-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,IAAM,gCAAgC,GAAG;IAC9C,OAAO,02WAwTR,CAAA;AACD,CAAC,CAAA"}
|