@teleporthq/teleport-plugin-next-data-source 0.43.66 → 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-mapper-cache-wiring.test.ts +11 -0
- 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__/data-source-request-locale.test.ts +313 -0
- 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__/gated-data-provider.test.ts +88 -0
- package/__tests__/items-path.test.ts +150 -0
- package/__tests__/localized-columns.test.ts +217 -0
- package/__tests__/numbered-pagination.test.ts +15 -0
- package/__tests__/product-filter-fields.ts +230 -0
- package/__tests__/product-filter-sql.fixture.json +7 -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__/refetch-loading-state.test.ts +23 -0
- package/__tests__/rest-api-response-cache.test.ts +434 -0
- package/__tests__/search-clear-button.test.ts +122 -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/content-localization.d.ts +37 -0
- package/dist/cjs/content-localization.d.ts.map +1 -0
- package/dist/cjs/content-localization.js +29 -0
- package/dist/cjs/content-localization.js.map +1 -0
- package/dist/cjs/count-effect.d.ts +11 -1
- package/dist/cjs/count-effect.d.ts.map +1 -1
- package/dist/cjs/count-effect.js +30 -2
- package/dist/cjs/count-effect.js.map +1 -1
- 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/airtable.d.ts.map +1 -1
- package/dist/cjs/fetchers/airtable.js +1 -1
- package/dist/cjs/fetchers/airtable.js.map +1 -1
- package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/cjs/fetchers/clickhouse.js +1 -1
- package/dist/cjs/fetchers/clickhouse.js.map +1 -1
- package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
- package/dist/cjs/fetchers/firestore.js +1 -1
- package/dist/cjs/fetchers/firestore.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/mariadb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mariadb.js +1 -1
- package/dist/cjs/fetchers/mariadb.js.map +1 -1
- package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mongodb.js +1 -1
- package/dist/cjs/fetchers/mongodb.js.map +1 -1
- package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
- package/dist/cjs/fetchers/mysql.js +1 -1
- package/dist/cjs/fetchers/mysql.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 +9 -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/redshift.d.ts.map +1 -1
- package/dist/cjs/fetchers/redshift.js +1 -1
- package/dist/cjs/fetchers/redshift.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 +16 -6
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/fetchers/turso.d.ts.map +1 -1
- package/dist/cjs/fetchers/turso.js +1 -1
- package/dist/cjs/fetchers/turso.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/index.d.ts +5 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +60 -8
- package/dist/cjs/index.js.map +1 -1
- 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/loading-state.d.ts +16 -1
- package/dist/cjs/loading-state.d.ts.map +1 -1
- package/dist/cjs/loading-state.js +69 -3
- package/dist/cjs/loading-state.js.map +1 -1
- package/dist/cjs/localized-columns.d.ts +56 -0
- package/dist/cjs/localized-columns.d.ts.map +1 -0
- package/dist/cjs/localized-columns.js +137 -0
- package/dist/cjs/localized-columns.js.map +1 -0
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +140 -50
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/product-filter-fields.d.ts +87 -0
- package/dist/cjs/product-filter-fields.d.ts.map +1 -0
- package/dist/cjs/product-filter-fields.js +161 -0
- package/dist/cjs/product-filter-fields.js.map +1 -0
- package/dist/cjs/request-locale.d.ts +49 -0
- package/dist/cjs/request-locale.d.ts.map +1 -0
- package/dist/cjs/request-locale.js +130 -0
- package/dist/cjs/request-locale.js.map +1 -0
- package/dist/cjs/search-clear.d.ts +31 -0
- package/dist/cjs/search-clear.d.ts.map +1 -0
- package/dist/cjs/search-clear.js +103 -0
- package/dist/cjs/search-clear.js.map +1 -0
- 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 +61 -4
- package/dist/cjs/transformations/index.d.ts.map +1 -1
- package/dist/cjs/transformations/index.js +69 -19
- 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 +11 -1
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +60 -16
- 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/content-localization.d.ts +37 -0
- package/dist/esm/content-localization.d.ts.map +1 -0
- package/dist/esm/content-localization.js +24 -0
- package/dist/esm/content-localization.js.map +1 -0
- package/dist/esm/count-effect.d.ts +11 -1
- package/dist/esm/count-effect.d.ts.map +1 -1
- package/dist/esm/count-effect.js +28 -1
- package/dist/esm/count-effect.js.map +1 -1
- 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/airtable.d.ts.map +1 -1
- package/dist/esm/fetchers/airtable.js +1 -1
- package/dist/esm/fetchers/airtable.js.map +1 -1
- package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/esm/fetchers/clickhouse.js +1 -1
- package/dist/esm/fetchers/clickhouse.js.map +1 -1
- package/dist/esm/fetchers/firestore.d.ts.map +1 -1
- package/dist/esm/fetchers/firestore.js +1 -1
- package/dist/esm/fetchers/firestore.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/mariadb.d.ts.map +1 -1
- package/dist/esm/fetchers/mariadb.js +1 -1
- package/dist/esm/fetchers/mariadb.js.map +1 -1
- package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
- package/dist/esm/fetchers/mongodb.js +1 -1
- package/dist/esm/fetchers/mongodb.js.map +1 -1
- package/dist/esm/fetchers/mysql.d.ts.map +1 -1
- package/dist/esm/fetchers/mysql.js +1 -1
- package/dist/esm/fetchers/mysql.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 +9 -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/redshift.d.ts.map +1 -1
- package/dist/esm/fetchers/redshift.js +1 -1
- package/dist/esm/fetchers/redshift.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 +16 -6
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/fetchers/turso.d.ts.map +1 -1
- package/dist/esm/fetchers/turso.js +1 -1
- package/dist/esm/fetchers/turso.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/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +55 -7
- package/dist/esm/index.js.map +1 -1
- 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/loading-state.d.ts +16 -1
- package/dist/esm/loading-state.d.ts.map +1 -1
- package/dist/esm/loading-state.js +69 -3
- package/dist/esm/loading-state.js.map +1 -1
- package/dist/esm/localized-columns.d.ts +56 -0
- package/dist/esm/localized-columns.d.ts.map +1 -0
- package/dist/esm/localized-columns.js +132 -0
- package/dist/esm/localized-columns.js.map +1 -0
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +141 -51
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/product-filter-fields.d.ts +87 -0
- package/dist/esm/product-filter-fields.d.ts.map +1 -0
- package/dist/esm/product-filter-fields.js +154 -0
- package/dist/esm/product-filter-fields.js.map +1 -0
- package/dist/esm/request-locale.d.ts +49 -0
- package/dist/esm/request-locale.d.ts.map +1 -0
- package/dist/esm/request-locale.js +98 -0
- package/dist/esm/request-locale.js.map +1 -0
- package/dist/esm/search-clear.d.ts +31 -0
- package/dist/esm/search-clear.d.ts.map +1 -0
- package/dist/esm/search-clear.js +74 -0
- package/dist/esm/search-clear.js.map +1 -0
- 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 +61 -4
- package/dist/esm/transformations/index.d.ts.map +1 -1
- package/dist/esm/transformations/index.js +69 -19
- 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 +11 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +60 -16
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/array-overlap-sql.ts +41 -0
- package/src/content-localization.ts +53 -0
- package/src/count-effect.ts +53 -2
- package/src/data-source-fetchers.ts +41 -5
- package/src/fetchers/airtable.ts +4 -2
- package/src/fetchers/clickhouse.ts +4 -2
- package/src/fetchers/firestore.ts +4 -2
- package/src/fetchers/javascript.ts +9 -1
- package/src/fetchers/mariadb.ts +4 -2
- package/src/fetchers/mongodb.ts +4 -2
- package/src/fetchers/mysql.ts +4 -2
- package/src/fetchers/postgresql.ts +53 -12
- package/src/fetchers/raw-query.ts +60 -5
- package/src/fetchers/redshift.ts +4 -2
- package/src/fetchers/rest-api.ts +27 -5
- package/src/fetchers/teleport.ts +85 -22
- package/src/fetchers/turso.ts +4 -2
- 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/index.ts +79 -11
- package/src/items-path.ts +74 -0
- package/src/loading-state.ts +134 -3
- package/src/localized-columns.ts +146 -0
- package/src/pagination-plugin.ts +206 -60
- package/src/product-filter-fields.ts +173 -0
- package/src/request-locale.ts +113 -0
- package/src/search-clear.ts +102 -0
- 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 +191 -23
- package/src/transformations/shared-utils.ts +6 -0
- package/src/utils.ts +109 -19
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Filtering a products list on things that are not a plain column.
|
|
4
|
+
*
|
|
5
|
+
* The storefront's product filters ask questions the `teleport_products` row
|
|
6
|
+
* cannot answer with a single column comparison: "what does it cost right now"
|
|
7
|
+
* (`price` net of a live markdown), "how many stars" (an aggregate over the
|
|
8
|
+
* reviews table), "is it on sale", and "does it come in size XL" (a value
|
|
9
|
+
* inside the `variant_options` JSON). Like the discount-aware sort in
|
|
10
|
+
* `product-price-sort.ts`, these have to be answered by the DATABASE — the list
|
|
11
|
+
* is paginated, so filtering the fetched page would only filter 20 of N rows.
|
|
12
|
+
*
|
|
13
|
+
* The editor emits such a filter as an ordinary condition whose `source` is
|
|
14
|
+
* one of the VIRTUAL field names below. Every SQL builder that can receive a
|
|
15
|
+
* products filter rewrites them into the expressions here:
|
|
16
|
+
*
|
|
17
|
+
* - this file → the generated store's `teleport_products` API route
|
|
18
|
+
* (`fetchers/teleport.ts`, `fetchers/postgresql.ts`);
|
|
19
|
+
* - `database-provider-worker/src/lib/product-filter-fields.ts` → the editor
|
|
20
|
+
* canvas. ⛔ A byte-for-byte mirror of the SQL below; both repos pin the
|
|
21
|
+
* strings with a test, because a clause the canvas cannot build is an HTTP
|
|
22
|
+
* 500 the canvas draws as an EMPTY grid.
|
|
23
|
+
*
|
|
24
|
+
* ## The expressions cannot raise
|
|
25
|
+
*
|
|
26
|
+
* Same discipline as the sort: the JSON column is cast only when its text
|
|
27
|
+
* already looks like an array, the axis key is validated against a slug pattern
|
|
28
|
+
* before it is bound, and an unknown key filters to no rows instead of erroring
|
|
29
|
+
* — a filter that the database rejects would empty the whole products page.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.generateProductFilterClauseHelper = exports.buildProductVariantAxisExistsSql = exports.SAFE_VARIANT_OPTIONS_JSONB = exports.buildProductOnSaleSql = exports.buildProductRatingBucketSql = exports.IN_OPERAND = exports.PRODUCT_VARIANT_AXIS_KEY_PATTERN = exports.PRODUCT_VARIANT_AXIS_FILTER_PREFIX = exports.PRODUCT_ON_SALE_FILTER_FIELD = exports.PRODUCT_RATING_FILTER_FIELD = exports.PRODUCT_REVIEWS_TABLE_NAME = void 0;
|
|
33
|
+
var product_price_sort_1 = require("./product-price-sort");
|
|
34
|
+
/** The reviews table the star-rating aggregate reads. Exists once reviews were enabled. */
|
|
35
|
+
exports.PRODUCT_REVIEWS_TABLE_NAME = 'teleport_product_reviews';
|
|
36
|
+
/** Virtual field: the product's star bucket — `ROUND(AVG(approved rating))`, 1..5, NULL when unreviewed. */
|
|
37
|
+
exports.PRODUCT_RATING_FILTER_FIELD = 'rating';
|
|
38
|
+
/** Virtual field: `'true'` while a markdown is live, else `'false'`. */
|
|
39
|
+
exports.PRODUCT_ON_SALE_FILTER_FIELD = 'on_sale';
|
|
40
|
+
/**
|
|
41
|
+
* Virtual field family: `variant_options.<axisKey>` — the product offers the
|
|
42
|
+
* axis (e.g. `size`) in one of the given values (e.g. `xl`).
|
|
43
|
+
*/
|
|
44
|
+
exports.PRODUCT_VARIANT_AXIS_FILTER_PREFIX = 'variant_options.';
|
|
45
|
+
/**
|
|
46
|
+
* What an axis key may look like. Keys are produced by the editor's slug
|
|
47
|
+
* helper (`deriveOptionKey`), so this is what every real key matches; anything
|
|
48
|
+
* else is refused before it can reach the database.
|
|
49
|
+
*/
|
|
50
|
+
exports.PRODUCT_VARIANT_AXIS_KEY_PATTERN = '^[a-z0-9][a-z0-9_-]{0,63}$';
|
|
51
|
+
/** Generic multi-value operand: the column equals ANY of the destination values. */
|
|
52
|
+
exports.IN_OPERAND = 'in';
|
|
53
|
+
/**
|
|
54
|
+
* `ROUND(AVG(rating))` over the product's APPROVED reviews. Only approved rows
|
|
55
|
+
* count — moderation is the merchant's veto — and the outer row is the
|
|
56
|
+
* unaliased `teleport_products` the fetchers select from.
|
|
57
|
+
*/
|
|
58
|
+
var buildProductRatingBucketSql = function () {
|
|
59
|
+
return "(SELECT ROUND(AVG(r.rating)) FROM ".concat(exports.PRODUCT_REVIEWS_TABLE_NAME, " r WHERE r.product_id = ").concat(product_price_sort_1.PRODUCTS_TABLE_NAME, ".id AND r.status = 'approved' AND r.rating IS NOT NULL)");
|
|
60
|
+
};
|
|
61
|
+
exports.buildProductRatingBucketSql = buildProductRatingBucketSql;
|
|
62
|
+
/** `'true'` when the price paid today is below the list price, i.e. a markdown is live. */
|
|
63
|
+
var buildProductOnSaleSql = function () {
|
|
64
|
+
return "(CASE WHEN ".concat((0, product_price_sort_1.buildProductEffectivePriceSql)(), " < \"price\"::numeric THEN 'true' ELSE 'false' END)");
|
|
65
|
+
};
|
|
66
|
+
exports.buildProductOnSaleSql = buildProductOnSaleSql;
|
|
67
|
+
/**
|
|
68
|
+
* Only text that already looks like a JSON array is cast; NULL, empty or a
|
|
69
|
+
* hand-edited scalar reads as "no variant axes".
|
|
70
|
+
*/
|
|
71
|
+
exports.SAFE_VARIANT_OPTIONS_JSONB = "CASE\n WHEN \"variant_options\" IS NULL OR btrim(\"variant_options\") NOT LIKE '[%' THEN '[]'::jsonb\n ELSE \"variant_options\"::jsonb\n END";
|
|
72
|
+
/**
|
|
73
|
+
* True when the product declares the axis bound to `keyParam` with at least one
|
|
74
|
+
* of the values bound to `valuesParam` (a `text[]`). Both are PARAMETERS, never
|
|
75
|
+
* interpolated text.
|
|
76
|
+
*/
|
|
77
|
+
var buildProductVariantAxisExistsSql = function (keyParam, valuesParam) {
|
|
78
|
+
return "EXISTS (SELECT 1 FROM jsonb_array_elements(".concat(exports.SAFE_VARIANT_OPTIONS_JSONB, ") AS ax, jsonb_array_elements(CASE WHEN jsonb_typeof(ax->'values') = 'array' THEN ax->'values' ELSE '[]'::jsonb END) AS v WHERE ax->>'key' = ").concat(keyParam, " AND v->>'value' = ANY(").concat(valuesParam, "::text[]))");
|
|
79
|
+
};
|
|
80
|
+
exports.buildProductVariantAxisExistsSql = buildProductVariantAxisExistsSql;
|
|
81
|
+
/**
|
|
82
|
+
* The complete `productFilterClause(field, operand, value, pushParam)` helper a
|
|
83
|
+
* SQL fetcher embeds in its generated route.
|
|
84
|
+
*
|
|
85
|
+
* Returns a finished WHERE clause for a virtual (or rewritten) products field,
|
|
86
|
+
* or `null` for anything else so the fetcher's ordinary branches run. `pushParam`
|
|
87
|
+
* binds a value and answers its `$n` placeholder. By the time it is called an
|
|
88
|
+
* `in` filter has been normalised to `=` with an ARRAY value (see
|
|
89
|
+
* `normalizeInOperand` in `utils.ts`), which reads as "any of". A virtual field
|
|
90
|
+
* never answers `null` once matched — an operand it cannot express filters to
|
|
91
|
+
* no rows rather than falling into a branch that would name a column the table
|
|
92
|
+
* does not have.
|
|
93
|
+
*
|
|
94
|
+
* Emitted through `JSON.stringify` and string concatenation only — no backtick
|
|
95
|
+
* and no `${` may appear in the output, which is interpolated into a fetcher's
|
|
96
|
+
* template literal. On a table that is not the products table the helper still
|
|
97
|
+
* exists and always answers `null`, so a fetcher can embed it unconditionally.
|
|
98
|
+
*/
|
|
99
|
+
var generateProductFilterClauseHelper = function (tableName) {
|
|
100
|
+
if (!(0, product_price_sort_1.supportsProductPriceSort)(tableName)) {
|
|
101
|
+
return [
|
|
102
|
+
'// Virtual products-table filter fields. This table has none, so every',
|
|
103
|
+
"// condition takes the fetcher's ordinary branches.",
|
|
104
|
+
'function productFilterClause() {',
|
|
105
|
+
' return null',
|
|
106
|
+
'}',
|
|
107
|
+
].join('\n');
|
|
108
|
+
}
|
|
109
|
+
var lines = [
|
|
110
|
+
"// Rewrites the products table's virtual filter fields - the price paid",
|
|
111
|
+
'// today, the star-rating bucket, the on-sale flag and a variant axis - into',
|
|
112
|
+
'// SQL. Answers null for a plain column so the ordinary branches run. An',
|
|
113
|
+
'// "in" filter arrives here already normalised to "=" with an ARRAY value.',
|
|
114
|
+
'function productFilterClause(field, operand, value, pushParam) {',
|
|
115
|
+
" var scalarOps = ['=', '!=', '>', '<', '>=', '<=']",
|
|
116
|
+
" var equalityOps = ['=', '!=']",
|
|
117
|
+
' var compare = function (expression, allowedOps, virtual) {',
|
|
118
|
+
' if (Array.isArray(value)) {',
|
|
119
|
+
" if (operand === '=') {",
|
|
120
|
+
" return expression + '::text = ANY(' + pushParam(value.map(String)) + '::text[])'",
|
|
121
|
+
' }',
|
|
122
|
+
" if (operand === '!=') {",
|
|
123
|
+
" return expression + '::text <> ALL(' + pushParam(value.map(String)) + '::text[])'",
|
|
124
|
+
' }',
|
|
125
|
+
" return virtual ? 'FALSE' : null",
|
|
126
|
+
' }',
|
|
127
|
+
" if (allowedOps.indexOf(operand) === -1) return virtual ? 'FALSE' : null",
|
|
128
|
+
" return expression + ' ' + operand + ' ' + pushParam(value)",
|
|
129
|
+
' }',
|
|
130
|
+
" if (field === ".concat(JSON.stringify(product_price_sort_1.PRODUCT_PRICE_SORT_FIELD), ") {"),
|
|
131
|
+
" return compare(".concat(JSON.stringify('(' + (0, product_price_sort_1.buildProductEffectivePriceSql)() + ')'), ", scalarOps, false)"),
|
|
132
|
+
' }',
|
|
133
|
+
" if (field === ".concat(JSON.stringify(exports.PRODUCT_RATING_FILTER_FIELD), ") {"),
|
|
134
|
+
" return compare(".concat(JSON.stringify((0, exports.buildProductRatingBucketSql)()), ", scalarOps, true)"),
|
|
135
|
+
' }',
|
|
136
|
+
" if (field === ".concat(JSON.stringify(exports.PRODUCT_ON_SALE_FILTER_FIELD), ") {"),
|
|
137
|
+
" return compare(".concat(JSON.stringify((0, exports.buildProductOnSaleSql)()), ", equalityOps, true)"),
|
|
138
|
+
' }',
|
|
139
|
+
" if (field.indexOf(".concat(JSON.stringify(exports.PRODUCT_VARIANT_AXIS_FILTER_PREFIX), ") === 0) {"),
|
|
140
|
+
" var axisKey = field.slice(".concat(exports.PRODUCT_VARIANT_AXIS_FILTER_PREFIX.length, ")"),
|
|
141
|
+
" if (!new RegExp(".concat(JSON.stringify(exports.PRODUCT_VARIANT_AXIS_KEY_PATTERN), ").test(axisKey)) {"),
|
|
142
|
+
' // Not a key the editor could have written: no rows, never an error.',
|
|
143
|
+
" return 'FALSE'",
|
|
144
|
+
' }',
|
|
145
|
+
" if (operand !== '=') return 'FALSE'",
|
|
146
|
+
' var values = (Array.isArray(value) ? value : [value]).map(String)',
|
|
147
|
+
' var keyParam = pushParam(axisKey)',
|
|
148
|
+
' var valuesParam = pushParam(values)',
|
|
149
|
+
" return ".concat(JSON.stringify((0, exports.buildProductVariantAxisExistsSql)('__KEY__', '__VALUES__'))),
|
|
150
|
+
// Function replacements: a "$1" inside a replacement STRING is a special
|
|
151
|
+
// pattern, so the placeholders are swapped by callback.
|
|
152
|
+
" .replace('__KEY__', function () { return keyParam })",
|
|
153
|
+
" .replace('__VALUES__', function () { return valuesParam })",
|
|
154
|
+
' }',
|
|
155
|
+
' return null',
|
|
156
|
+
'}',
|
|
157
|
+
];
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
};
|
|
160
|
+
exports.generateProductFilterClauseHelper = generateProductFilterClauseHelper;
|
|
161
|
+
//# sourceMappingURL=product-filter-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-filter-fields.js","sourceRoot":"","sources":["../../src/product-filter-fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as types from '@babel/types';
|
|
2
|
+
import type { UIDLDependency } from '@teleporthq/teleport-types';
|
|
3
|
+
/**
|
|
4
|
+
* How a generated data-source fetch says which language it is for.
|
|
5
|
+
*
|
|
6
|
+
* A multi-language project stores a translatable column once per language
|
|
7
|
+
* (`name`, `es_name`, …) and the generated fetcher resolves each row against
|
|
8
|
+
* ONE of them (see `transformations/` and `localized-columns.ts`). Nothing
|
|
9
|
+
* about the API route knows the page it serves — an API route has no locale
|
|
10
|
+
* segment in its URL — so the page tells it, through this query parameter:
|
|
11
|
+
*
|
|
12
|
+
* - a client-side fetch (`DataProvider` `params`) sends `router.locale`;
|
|
13
|
+
* - a build-time fetch inside `getStaticProps` sends `context.locale`.
|
|
14
|
+
*
|
|
15
|
+
* Both are what Next.js resolved from the `/es/...` route, so the rows a page
|
|
16
|
+
* renders are in the language the page is in. The same name the details-page
|
|
17
|
+
* fetch (`teleport-plugin-next-static-props`) has always sent.
|
|
18
|
+
*/
|
|
19
|
+
export declare const REQUEST_LOCALE_PARAM = "locale";
|
|
20
|
+
/**
|
|
21
|
+
* `router?.locale` — the client's current locale. Optional-chained like every
|
|
22
|
+
* other generated `router` read: `useRouter()` answers `null` during a static
|
|
23
|
+
* export's first paint.
|
|
24
|
+
*/
|
|
25
|
+
export declare const buildClientLocaleExpression: () => types.Expression;
|
|
26
|
+
/** `locale: router?.locale` — the param of a client-side fetch. */
|
|
27
|
+
export declare const buildClientLocaleParam: () => types.ObjectProperty;
|
|
28
|
+
/** `locale: context.locale` — the param of a fetch inside getStaticProps. */
|
|
29
|
+
export declare const buildServerLocaleParam: () => types.ObjectProperty;
|
|
30
|
+
/** Whether an object literal already carries the locale param. */
|
|
31
|
+
export declare const hasLocaleParam: (properties: types.ObjectExpression['properties']) => boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Adds the client locale to a fetch's params, once, and to the `useMemo` deps
|
|
34
|
+
* that must rebuild them: a locale switch is a client-side transition on the
|
|
35
|
+
* SAME page instance, so only a dependency change refetches the rows in the
|
|
36
|
+
* new language.
|
|
37
|
+
*/
|
|
38
|
+
export declare const appendClientLocaleParam: (paramsProps: types.ObjectExpression['properties'], memoDeps: types.Expression[]) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Puts `const router = useRouter()` (and its import) in scope, once.
|
|
41
|
+
*
|
|
42
|
+
* Idempotent with every sibling plugin that declares the same hook — the i18n
|
|
43
|
+
* locale mapper, the URL search-params plugin and the base component plugin
|
|
44
|
+
* all guard on the same identifier, so whichever runs first wins and the rest
|
|
45
|
+
* find it in place. Unshifted to the top of the body: nothing reads it before
|
|
46
|
+
* an effect runs, and hooks must not sit below a conditional return.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ensureRouterDeclaration: (body: types.Statement[], dependencies: Record<string, UIDLDependency>) => void;
|
|
49
|
+
//# sourceMappingURL=request-locale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-locale.d.ts","sourceRoot":"","sources":["../../src/request-locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAA;AAU5C;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,QAAO,MAAM,UAMlD,CAAA;AAEH,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,QAAO,MAAM,cAC6C,CAAA;AAE7F,6EAA6E;AAC7E,eAAO,MAAM,sBAAsB,QAAO,MAAM,cAI7C,CAAA;AAEH,kEAAkE;AAClE,eAAO,MAAM,cAAc,eAAgB,MAAM,gBAAgB,CAAC,YAAY,CAAC,KAAG,OAM/E,CAAA;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,gBACrB,MAAM,gBAAgB,CAAC,YAAY,CAAC,YACvC,MAAM,UAAU,EAAE,KAC3B,IAKF,CAAA;AASD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,SAC5B,MAAM,SAAS,EAAE,gBACT,OAAO,MAAM,EAAE,cAAc,CAAC,KAC3C,IAeF,CAAA"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.ensureRouterDeclaration = exports.appendClientLocaleParam = exports.hasLocaleParam = exports.buildServerLocaleParam = exports.buildClientLocaleParam = exports.buildClientLocaleExpression = exports.REQUEST_LOCALE_PARAM = void 0;
|
|
38
|
+
var types = __importStar(require("@babel/types"));
|
|
39
|
+
/**
|
|
40
|
+
* How a generated data-source fetch says which language it is for.
|
|
41
|
+
*
|
|
42
|
+
* A multi-language project stores a translatable column once per language
|
|
43
|
+
* (`name`, `es_name`, …) and the generated fetcher resolves each row against
|
|
44
|
+
* ONE of them (see `transformations/` and `localized-columns.ts`). Nothing
|
|
45
|
+
* about the API route knows the page it serves — an API route has no locale
|
|
46
|
+
* segment in its URL — so the page tells it, through this query parameter:
|
|
47
|
+
*
|
|
48
|
+
* - a client-side fetch (`DataProvider` `params`) sends `router.locale`;
|
|
49
|
+
* - a build-time fetch inside `getStaticProps` sends `context.locale`.
|
|
50
|
+
*
|
|
51
|
+
* Both are what Next.js resolved from the `/es/...` route, so the rows a page
|
|
52
|
+
* renders are in the language the page is in. The same name the details-page
|
|
53
|
+
* fetch (`teleport-plugin-next-static-props`) has always sent.
|
|
54
|
+
*/
|
|
55
|
+
exports.REQUEST_LOCALE_PARAM = 'locale';
|
|
56
|
+
/** The dependency behind the `router` every client-side locale read closes over. */
|
|
57
|
+
var USE_ROUTER_DEPENDENCY = {
|
|
58
|
+
type: 'library',
|
|
59
|
+
path: 'next/router',
|
|
60
|
+
version: '^12.1.10',
|
|
61
|
+
meta: { namedImport: true },
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* `router?.locale` — the client's current locale. Optional-chained like every
|
|
65
|
+
* other generated `router` read: `useRouter()` answers `null` during a static
|
|
66
|
+
* export's first paint.
|
|
67
|
+
*/
|
|
68
|
+
var buildClientLocaleExpression = function () {
|
|
69
|
+
return types.optionalMemberExpression(types.identifier('router'), types.identifier('locale'), false, true);
|
|
70
|
+
};
|
|
71
|
+
exports.buildClientLocaleExpression = buildClientLocaleExpression;
|
|
72
|
+
/** `locale: router?.locale` — the param of a client-side fetch. */
|
|
73
|
+
var buildClientLocaleParam = function () {
|
|
74
|
+
return types.objectProperty(types.identifier(exports.REQUEST_LOCALE_PARAM), (0, exports.buildClientLocaleExpression)());
|
|
75
|
+
};
|
|
76
|
+
exports.buildClientLocaleParam = buildClientLocaleParam;
|
|
77
|
+
/** `locale: context.locale` — the param of a fetch inside getStaticProps. */
|
|
78
|
+
var buildServerLocaleParam = function () {
|
|
79
|
+
return types.objectProperty(types.identifier(exports.REQUEST_LOCALE_PARAM), types.memberExpression(types.identifier('context'), types.identifier('locale')));
|
|
80
|
+
};
|
|
81
|
+
exports.buildServerLocaleParam = buildServerLocaleParam;
|
|
82
|
+
/** Whether an object literal already carries the locale param. */
|
|
83
|
+
var hasLocaleParam = function (properties) {
|
|
84
|
+
return properties.some(function (property) {
|
|
85
|
+
return property.type === 'ObjectProperty' &&
|
|
86
|
+
((property.key.type === 'Identifier' && property.key.name === exports.REQUEST_LOCALE_PARAM) ||
|
|
87
|
+
(property.key.type === 'StringLiteral' && property.key.value === exports.REQUEST_LOCALE_PARAM));
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
exports.hasLocaleParam = hasLocaleParam;
|
|
91
|
+
/**
|
|
92
|
+
* Adds the client locale to a fetch's params, once, and to the `useMemo` deps
|
|
93
|
+
* that must rebuild them: a locale switch is a client-side transition on the
|
|
94
|
+
* SAME page instance, so only a dependency change refetches the rows in the
|
|
95
|
+
* new language.
|
|
96
|
+
*/
|
|
97
|
+
var appendClientLocaleParam = function (paramsProps, memoDeps) {
|
|
98
|
+
if (!(0, exports.hasLocaleParam)(paramsProps)) {
|
|
99
|
+
paramsProps.push((0, exports.buildClientLocaleParam)());
|
|
100
|
+
}
|
|
101
|
+
memoDeps.push((0, exports.buildClientLocaleExpression)());
|
|
102
|
+
};
|
|
103
|
+
exports.appendClientLocaleParam = appendClientLocaleParam;
|
|
104
|
+
/** Any declaration of `router` — a second one, however it is initialised, is a syntax error. */
|
|
105
|
+
var declaresRouter = function (statement) {
|
|
106
|
+
return statement.type === 'VariableDeclaration' &&
|
|
107
|
+
statement.declarations.some(function (declaration) { return declaration.id.type === 'Identifier' && declaration.id.name === 'router'; });
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Puts `const router = useRouter()` (and its import) in scope, once.
|
|
111
|
+
*
|
|
112
|
+
* Idempotent with every sibling plugin that declares the same hook — the i18n
|
|
113
|
+
* locale mapper, the URL search-params plugin and the base component plugin
|
|
114
|
+
* all guard on the same identifier, so whichever runs first wins and the rest
|
|
115
|
+
* find it in place. Unshifted to the top of the body: nothing reads it before
|
|
116
|
+
* an effect runs, and hooks must not sit below a conditional return.
|
|
117
|
+
*/
|
|
118
|
+
var ensureRouterDeclaration = function (body, dependencies) {
|
|
119
|
+
if (!dependencies.useRouter) {
|
|
120
|
+
dependencies.useRouter = __assign({}, USE_ROUTER_DEPENDENCY);
|
|
121
|
+
}
|
|
122
|
+
if (body.some(declaresRouter)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
body.unshift(types.variableDeclaration('const', [
|
|
126
|
+
types.variableDeclarator(types.identifier('router'), types.callExpression(types.identifier('useRouter'), [])),
|
|
127
|
+
]));
|
|
128
|
+
};
|
|
129
|
+
exports.ensureRouterDeclaration = ensureRouterDeclaration;
|
|
130
|
+
//# sourceMappingURL=request-locale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-locale.js","sourceRoot":"","sources":["../../src/request-locale.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "clear search" button a listing's search field carries — marked
|
|
3
|
+
* `data-tq-search-clear` by the editor (`listing-search-field.ts`), the same
|
|
4
|
+
* marker the canvas renderer acts on. The search keyword is the mapper's own
|
|
5
|
+
* React state, which no authored workflow can reach, so the generator wires
|
|
6
|
+
* the button here: a click empties the query, and the button renders only
|
|
7
|
+
* while the query is non-empty.
|
|
8
|
+
*
|
|
9
|
+
* A button belongs to the search input it shares a parent with — the field
|
|
10
|
+
* wrapper — never to "the next search-enabled mapper": a page with two lists
|
|
11
|
+
* and one clear button would otherwise wire it to the wrong list.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SEARCH_CLEAR_ATTR = "data-tq-search-clear";
|
|
14
|
+
export interface SearchClearButton {
|
|
15
|
+
node: any;
|
|
16
|
+
parent: any;
|
|
17
|
+
index: number;
|
|
18
|
+
}
|
|
19
|
+
/** Every marked button under `root`, with the JSX parent and child index it sits at. */
|
|
20
|
+
export declare function findAllSearchClearButtonsInJSX(root: any): SearchClearButton[];
|
|
21
|
+
/** The search input the button shares its parent with, or null. */
|
|
22
|
+
export declare function findSiblingSearchInput(button: SearchClearButton, searchInputs: any[]): any | null;
|
|
23
|
+
/**
|
|
24
|
+
* Wires one button: `onClick` empties the query, and the element is replaced
|
|
25
|
+
* in its parent by `{query ? <button…/> : null}`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function wireSearchClearButton(button: SearchClearButton, vars: {
|
|
28
|
+
searchQueryVar: string;
|
|
29
|
+
setSearchQueryVar: string;
|
|
30
|
+
}): void;
|
|
31
|
+
//# sourceMappingURL=search-clear.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-clear.d.ts","sourceRoot":"","sources":["../../src/search-clear.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,iBAAiB,yBAAyB,CAAA;AAIvD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAQD,wFAAwF;AACxF,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,GAAG,GAAG,iBAAiB,EAAE,CAqC7E;AAED,mEAAmE;AACnE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,CAGjG;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAC1D,IAAI,CAgBN"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.wireSearchClearButton = exports.findSiblingSearchInput = exports.findAllSearchClearButtonsInJSX = exports.SEARCH_CLEAR_ATTR = void 0;
|
|
27
|
+
var types = __importStar(require("@babel/types"));
|
|
28
|
+
var pagination_controls_1 = require("./pagination-controls");
|
|
29
|
+
/**
|
|
30
|
+
* The "clear search" button a listing's search field carries — marked
|
|
31
|
+
* `data-tq-search-clear` by the editor (`listing-search-field.ts`), the same
|
|
32
|
+
* marker the canvas renderer acts on. The search keyword is the mapper's own
|
|
33
|
+
* React state, which no authored workflow can reach, so the generator wires
|
|
34
|
+
* the button here: a click empties the query, and the button renders only
|
|
35
|
+
* while the query is non-empty.
|
|
36
|
+
*
|
|
37
|
+
* A button belongs to the search input it shares a parent with — the field
|
|
38
|
+
* wrapper — never to "the next search-enabled mapper": a page with two lists
|
|
39
|
+
* and one clear button would otherwise wire it to the wrong list.
|
|
40
|
+
*/
|
|
41
|
+
exports.SEARCH_CLEAR_ATTR = 'data-tq-search-clear';
|
|
42
|
+
function hasSearchClearMarker(node) {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
return !!((_b = (_a = node === null || node === void 0 ? void 0 : node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.some(function (attr) { var _a; return attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === exports.SEARCH_CLEAR_ATTR; }));
|
|
45
|
+
}
|
|
46
|
+
/** Every marked button under `root`, with the JSX parent and child index it sits at. */
|
|
47
|
+
function findAllSearchClearButtonsInJSX(root) {
|
|
48
|
+
var results = [];
|
|
49
|
+
var traverse = function (node) {
|
|
50
|
+
if (!node) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (node.type === 'JSXElement' && Array.isArray(node.children)) {
|
|
54
|
+
node.children.forEach(function (child, index) {
|
|
55
|
+
if ((child === null || child === void 0 ? void 0 : child.type) === 'JSXElement' && hasSearchClearMarker(child)) {
|
|
56
|
+
results.push({ node: child, parent: node, index: index });
|
|
57
|
+
}
|
|
58
|
+
traverse(child);
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (node.body) {
|
|
63
|
+
if (Array.isArray(node.body)) {
|
|
64
|
+
node.body.forEach(function (statement) { return traverse(statement); });
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
traverse(node.body);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (node.consequent) {
|
|
71
|
+
traverse(node.consequent);
|
|
72
|
+
}
|
|
73
|
+
if (node.alternate) {
|
|
74
|
+
traverse(node.alternate);
|
|
75
|
+
}
|
|
76
|
+
if (node.expression) {
|
|
77
|
+
traverse(node.expression);
|
|
78
|
+
}
|
|
79
|
+
if (node.argument) {
|
|
80
|
+
traverse(node.argument);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
traverse(root);
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
exports.findAllSearchClearButtonsInJSX = findAllSearchClearButtonsInJSX;
|
|
87
|
+
/** The search input the button shares its parent with, or null. */
|
|
88
|
+
function findSiblingSearchInput(button, searchInputs) {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
var siblings = (_a = button.parent.children) !== null && _a !== void 0 ? _a : [];
|
|
91
|
+
return (_b = siblings.find(function (sibling) { return searchInputs.includes(sibling); })) !== null && _b !== void 0 ? _b : null;
|
|
92
|
+
}
|
|
93
|
+
exports.findSiblingSearchInput = findSiblingSearchInput;
|
|
94
|
+
/**
|
|
95
|
+
* Wires one button: `onClick` empties the query, and the element is replaced
|
|
96
|
+
* in its parent by `{query ? <button…/> : null}`.
|
|
97
|
+
*/
|
|
98
|
+
function wireSearchClearButton(button, vars) {
|
|
99
|
+
(0, pagination_controls_1.setJSXExpressionAttribute)(button.node, 'onClick', types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setSearchQueryVar), [types.stringLiteral('')])));
|
|
100
|
+
button.parent.children[button.index] = types.jsxExpressionContainer(types.conditionalExpression(types.identifier(vars.searchQueryVar), button.node, types.nullLiteral()));
|
|
101
|
+
}
|
|
102
|
+
exports.wireSearchClearButton = wireSearchClearButton;
|
|
103
|
+
//# sourceMappingURL=search-clear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-clear.js","sourceRoot":"","sources":["../../src/search-clear.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAAqC;AACrC,6DAAiE;AAEjE;;;;;;;;;;;GAWG;AAEU,QAAA,iBAAiB,GAAG,sBAAsB,CAAA;AAUvD,SAAS,oBAAoB,CAAC,IAAS;;IACrC,OAAO,CAAC,CAAC,CAAA,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,cAAc,0CAAE,UAAU,0CAAE,IAAI,CAC7C,UAAC,IAAS,YAAK,OAAA,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,IAAI,MAAK,yBAAiB,CAAA,EAAA,CACrF,CAAA,CAAA;AACH,CAAC;AAED,wFAAwF;AACxF,SAAgB,8BAA8B,CAAC,IAAS;IACtD,IAAM,OAAO,GAAwB,EAAE,CAAA;IACvC,IAAM,QAAQ,GAAG,UAAC,IAAS;QACzB,IAAI,CAAC,IAAI,EAAE;YACT,OAAM;SACP;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;YAC9D,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAC,KAAU,EAAE,KAAa;gBAC9C,IAAI,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,MAAK,YAAY,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE;oBAC/D,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,OAAA,EAAE,CAAC,CAAA;iBACnD;gBACD,QAAQ,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,CAAC,CAAA;YACF,OAAM;SACP;QACD,IAAI,IAAI,CAAC,IAAI,EAAE;YACb,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,SAAc,IAAK,OAAA,QAAQ,CAAC,SAAS,CAAC,EAAnB,CAAmB,CAAC,CAAA;aAC3D;iBAAM;gBACL,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;aACpB;SACF;QACD,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;SAC1B;QACD,IAAI,IAAI,CAAC,SAAS,EAAE;YAClB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;SACzB;QACD,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;SAC1B;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE;YACjB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;SACxB;IACH,CAAC,CAAA;IACD,QAAQ,CAAC,IAAI,CAAC,CAAA;IACd,OAAO,OAAO,CAAA;AAChB,CAAC;AArCD,wEAqCC;AAED,mEAAmE;AACnE,SAAgB,sBAAsB,CAAC,MAAyB,EAAE,YAAmB;;IACnF,IAAM,QAAQ,GAAU,MAAA,MAAM,CAAC,MAAM,CAAC,QAAQ,mCAAI,EAAE,CAAA;IACpD,OAAO,MAAA,QAAQ,CAAC,IAAI,CAAC,UAAC,OAAO,IAAK,OAAA,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAA9B,CAA8B,CAAC,mCAAI,IAAI,CAAA;AAC3E,CAAC;AAHD,wDAGC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,MAAyB,EACzB,IAA2D;IAE3D,IAAA,+CAAyB,EACvB,MAAM,CAAC,IAAI,EACX,SAAS,EACT,KAAK,CAAC,uBAAuB,CAC3B,EAAE,EACF,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAC1F,CACF,CAAA;IACD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,sBAAsB,CACjE,KAAK,CAAC,qBAAqB,CACzB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,EACrC,MAAM,CAAC,IAAI,EACX,KAAK,CAAC,WAAW,EAAE,CACpB,CACF,CAAA;AACH,CAAC;AAnBD,sDAmBC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates the code that finds a post's neighbours for its "previous / next"
|
|
3
|
+
* navigation: the published posts right before and after it in the order the
|
|
4
|
+
* blog listing shows them (`created_at`, then `id`, newest first). "Previous"
|
|
5
|
+
* is the older one.
|
|
6
|
+
*
|
|
7
|
+
* Only a post DETAILS fetch (a single record) asks. A neighbour whose row
|
|
8
|
+
* carries a redirect is skipped — linking to it would only bounce the reader
|
|
9
|
+
* somewhere else — which is read off the row in code rather than in SQL, so a
|
|
10
|
+
* table provisioned before the SEO columns still works.
|
|
11
|
+
*
|
|
12
|
+
* MUST mirror `findAdjacentBlogPosts` in teleport-gui
|
|
13
|
+
* `packages/renderer/src/utils/blog-adjacent-posts.ts` (the canvas).
|
|
14
|
+
*/
|
|
15
|
+
export declare const generateAdjacentPostsCode: () => string;
|
|
16
|
+
//# sourceMappingURL=blog-adjacent-posts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-adjacent-posts.d.ts","sourceRoot":"","sources":["../../../src/transformations/blog-adjacent-posts.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,QAAO,MAqD5C,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAdjacentPostsCode = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* How many posts each direction is read, so a neighbour that only REDIRECTS
|
|
6
|
+
* elsewhere can be stepped over without a second query.
|
|
7
|
+
*/
|
|
8
|
+
var ADJACENT_POST_CANDIDATES = 5;
|
|
9
|
+
/**
|
|
10
|
+
* Generates the code that finds a post's neighbours for its "previous / next"
|
|
11
|
+
* navigation: the published posts right before and after it in the order the
|
|
12
|
+
* blog listing shows them (`created_at`, then `id`, newest first). "Previous"
|
|
13
|
+
* is the older one.
|
|
14
|
+
*
|
|
15
|
+
* Only a post DETAILS fetch (a single record) asks. A neighbour whose row
|
|
16
|
+
* carries a redirect is skipped — linking to it would only bounce the reader
|
|
17
|
+
* somewhere else — which is read off the row in code rather than in SQL, so a
|
|
18
|
+
* table provisioned before the SEO columns still works.
|
|
19
|
+
*
|
|
20
|
+
* MUST mirror `findAdjacentBlogPosts` in teleport-gui
|
|
21
|
+
* `packages/renderer/src/utils/blog-adjacent-posts.ts` (the canvas).
|
|
22
|
+
*/
|
|
23
|
+
var generateAdjacentPostsCode = function () { return "\nvar BLOG_ADJACENT_CANDIDATES = ".concat(ADJACENT_POST_CANDIDATES, "\n\nfunction blogAdjacentPostsSql(comparison, direction) {\n return (\n 'SELECT p.* FROM teleport_blog_posts p,' +\n ' (SELECT created_at, id FROM teleport_blog_posts WHERE id = $1) cur' +\n \" WHERE p.status = 'published' AND (p.created_at, p.id) \" + comparison + ' (cur.created_at, cur.id)' +\n ' ORDER BY p.created_at ' + direction + ', p.id ' + direction +\n ' LIMIT ' + BLOG_ADJACENT_CANDIDATES\n )\n}\n\nfunction firstLinkableBlogPost(result) {\n var rows = result && Array.isArray(result.rows) ? result.rows : []\n for (var i = 0; i < rows.length; i++) {\n var row = rows[i]\n if (!row) continue\n var redirect = pickFirst(row.redirect_url, row.redirectUrl)\n if (typeof redirect === 'string' && redirect.trim() !== '') continue\n // Through JSON, like the rows the fetcher itself hands the transform.\n return JSON.parse(JSON.stringify(row))\n }\n return null\n}\n\n// { [postId]: { previous, next } } \u2014 raw rows or null \u2014 for a single-record\n// fetch; {} otherwise and on any failure (the navigation then hides).\nasync function getAdjacentPostsMap(getClientFn, records) {\n var map = {}\n if (!Array.isArray(records) || records.length !== 1) return map\n var postId = records[0] && records[0].id\n if (postId === null || postId === undefined) return map\n\n var client\n try {\n client = getClientFn()\n await client.connect()\n var older = await client.query(blogAdjacentPostsSql('<', 'DESC'), [String(postId)])\n var newer = await client.query(blogAdjacentPostsSql('>', 'ASC'), [String(postId)])\n map[String(postId)] = {\n previous: firstLinkableBlogPost(older),\n next: firstLinkableBlogPost(newer),\n }\n } catch (e) {\n // Leaves the navigation hidden.\n } finally {\n if (client) {\n try { await client.end() } catch (e) { /* ignore */ }\n }\n }\n return map\n}\n"); };
|
|
24
|
+
exports.generateAdjacentPostsCode = generateAdjacentPostsCode;
|
|
25
|
+
//# sourceMappingURL=blog-adjacent-posts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-adjacent-posts.js","sourceRoot":"","sources":["../../../src/transformations/blog-adjacent-posts.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,IAAM,wBAAwB,GAAG,CAAC,CAAA;AAElC;;;;;;;;;;;;;GAaG;AACI,IAAM,yBAAyB,GAAG,cAAc,OAAA,2CACtB,wBAAwB,g2DAoDxD,EArDsD,CAqDtD,CAAA;AArDY,QAAA,yBAAyB,6BAqDrC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many TOP-LEVEL comments a post page carries: the newest ones, shown
|
|
3
|
+
* oldest-first, each with all of its replies. The count in the section's
|
|
4
|
+
* heading still counts every approved comment.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ PAIRED with `BLOG_COMMENTS_RENDER_LIMIT` in teleport-gui
|
|
7
|
+
* `features/blog/constants/blog-comments.ts` (the canvas mirror).
|
|
8
|
+
*/
|
|
9
|
+
export declare const BLOG_COMMENTS_RENDER_LIMIT = 200;
|
|
10
|
+
/**
|
|
11
|
+
* Generates the code that loads and shapes a post's approved comments.
|
|
12
|
+
*
|
|
13
|
+
* Read server-side, with the post: only a post DETAILS fetch (a single record)
|
|
14
|
+
* asks, so a listing never pays for it, and the comments arrive in the page's
|
|
15
|
+
* HTML — rendered by SSR/ISR, carried along a client-side navigation to another
|
|
16
|
+
* post, no request of their own.
|
|
17
|
+
*
|
|
18
|
+
* Public columns only. `teleport_blog_comments` holds the commenters' email
|
|
19
|
+
* addresses and the comments still waiting for approval, which is why it is a
|
|
20
|
+
* customer-record table no browser may read (see teleport-shared's
|
|
21
|
+
* `table-access.ts`); nothing here selects either.
|
|
22
|
+
*
|
|
23
|
+
* Replies are one level deep: a reply whose parent is not among the rows (not
|
|
24
|
+
* approved, deleted) is dropped rather than promoted to the top level.
|
|
25
|
+
*
|
|
26
|
+
* MUST mirror `buildBlogComments` in teleport-gui
|
|
27
|
+
* `packages/renderer/src/utils/blog-comments.ts` (the canvas).
|
|
28
|
+
*/
|
|
29
|
+
export declare const generateBlogCommentsCode: () => string;
|
|
30
|
+
//# sourceMappingURL=blog-comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-comments.d.ts","sourceRoot":"","sources":["../../../src/transformations/blog-comments.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,MAAM,CAAA;AAE7C;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,wBAAwB,QAAO,MAsG3C,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateBlogCommentsCode = exports.BLOG_COMMENTS_RENDER_LIMIT = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* How many TOP-LEVEL comments a post page carries: the newest ones, shown
|
|
6
|
+
* oldest-first, each with all of its replies. The count in the section's
|
|
7
|
+
* heading still counts every approved comment.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ PAIRED with `BLOG_COMMENTS_RENDER_LIMIT` in teleport-gui
|
|
10
|
+
* `features/blog/constants/blog-comments.ts` (the canvas mirror).
|
|
11
|
+
*/
|
|
12
|
+
exports.BLOG_COMMENTS_RENDER_LIMIT = 200;
|
|
13
|
+
/**
|
|
14
|
+
* Generates the code that loads and shapes a post's approved comments.
|
|
15
|
+
*
|
|
16
|
+
* Read server-side, with the post: only a post DETAILS fetch (a single record)
|
|
17
|
+
* asks, so a listing never pays for it, and the comments arrive in the page's
|
|
18
|
+
* HTML — rendered by SSR/ISR, carried along a client-side navigation to another
|
|
19
|
+
* post, no request of their own.
|
|
20
|
+
*
|
|
21
|
+
* Public columns only. `teleport_blog_comments` holds the commenters' email
|
|
22
|
+
* addresses and the comments still waiting for approval, which is why it is a
|
|
23
|
+
* customer-record table no browser may read (see teleport-shared's
|
|
24
|
+
* `table-access.ts`); nothing here selects either.
|
|
25
|
+
*
|
|
26
|
+
* Replies are one level deep: a reply whose parent is not among the rows (not
|
|
27
|
+
* approved, deleted) is dropped rather than promoted to the top level.
|
|
28
|
+
*
|
|
29
|
+
* MUST mirror `buildBlogComments` in teleport-gui
|
|
30
|
+
* `packages/renderer/src/utils/blog-comments.ts` (the canvas).
|
|
31
|
+
*/
|
|
32
|
+
var generateBlogCommentsCode = function () { return "\nvar BLOG_COMMENTS_RENDER_LIMIT = ".concat(exports.BLOG_COMMENTS_RENDER_LIMIT, "\n\nvar BLOG_COMMENTS_SQL =\n 'WITH top AS (' +\n ' SELECT id FROM teleport_blog_comments' +\n \" WHERE post_id = $1 AND parent_id IS NULL AND status = 'approved'\" +\n ' ORDER BY created_at DESC, id DESC LIMIT ' + BLOG_COMMENTS_RENDER_LIMIT +\n ')' +\n ' SELECT c.id, c.parent_id, c.author_name, c.content, c.is_author_reply, c.created_at' +\n ' FROM teleport_blog_comments c' +\n \" WHERE c.post_id = $1 AND c.status = 'approved'\" +\n ' AND (c.id IN (SELECT id FROM top) OR c.parent_id IN (SELECT id FROM top))' +\n ' ORDER BY c.created_at ASC, c.id ASC'\n\n// Every approved comment the page could show \u2014 a reply counts only while the\n// comment it answers is approved too.\nvar BLOG_COMMENTS_COUNT_SQL =\n 'SELECT COUNT(*) AS n FROM teleport_blog_comments c' +\n \" WHERE c.post_id = $1 AND c.status = 'approved'\" +\n ' AND (c.parent_id IS NULL OR EXISTS (' +\n ' SELECT 1 FROM teleport_blog_comments p' +\n \" WHERE p.id = c.parent_id AND p.status = 'approved'))\"\n\nfunction blogAuthorInitials(name) {\n if (typeof name !== 'string') return ''\n var words = name.trim().split(' ').filter(function(word) { return word !== '' })\n if (words.length === 0) return ''\n // Code points, not UTF-16 units: an initial may be an emoji or a letter\n // outside the BMP, and half of a surrogate pair renders as a box.\n var first = Array.from(words[0])[0] || ''\n var last = words.length > 1 ? Array.from(words[words.length - 1])[0] || '' : ''\n return (first + last).toUpperCase()\n}\n\nfunction buildBlogComment(row) {\n var name = typeof row.author_name === 'string' ? row.author_name.trim() : ''\n var authorName = name || 'Reader'\n return {\n id: String(row.id),\n authorName: authorName,\n authorInitials: blogAuthorInitials(authorName),\n content: typeof row.content === 'string' ? row.content : '',\n createdAt: normalizeTimestamp(row.created_at),\n isAuthorReply: coerceBoolean(row.is_author_reply, false),\n }\n}\n\nfunction isTopLevelComment(row) {\n return row.parent_id === null || row.parent_id === undefined || row.parent_id === ''\n}\n\nfunction buildBlogComments(rows) {\n var comments = []\n if (!Array.isArray(rows)) return comments\n var byId = {}\n for (var i = 0; i < rows.length; i++) {\n var row = rows[i]\n if (!row || row.id == null || !isTopLevelComment(row)) continue\n var comment = buildBlogComment(row)\n comment.replies = []\n byId[comment.id] = comment\n comments.push(comment)\n }\n for (var j = 0; j < rows.length; j++) {\n var reply = rows[j]\n if (!reply || reply.id == null || isTopLevelComment(reply)) continue\n var parent = byId[String(reply.parent_id)]\n if (parent) parent.replies.push(buildBlogComment(reply))\n }\n return comments\n}\n\n// { [postId]: { rows, count } } for a single-record (details) fetch; {} for\n// anything else, and on any failure \u2014 a blog whose comments table does not\n// exist yet renders its posts without comments rather than failing the page.\nasync function getBlogCommentsMap(getClientFn, records) {\n var map = {}\n if (!Array.isArray(records) || records.length !== 1) return map\n var postId = records[0] && records[0].id\n if (postId === null || postId === undefined) return map\n\n var client\n try {\n client = getClientFn()\n await client.connect()\n var listed = await client.query(BLOG_COMMENTS_SQL, [String(postId)])\n var counted = await client.query(BLOG_COMMENTS_COUNT_SQL, [String(postId)])\n // Through JSON, like every other row the fetcher hands the transform: the\n // driver returns timestamps as Date objects.\n var rows = listed && Array.isArray(listed.rows) ? JSON.parse(JSON.stringify(listed.rows)) : []\n var count = counted && counted.rows && counted.rows[0] ? Number(counted.rows[0].n) : NaN\n map[String(postId)] = { rows: rows, count: isNaN(count) ? rows.length : count }\n } catch (e) {\n // Leaves the post without comments.\n } finally {\n if (client) {\n try { await client.end() } catch (e) { /* ignore */ }\n }\n }\n return map\n}\n"); };
|
|
33
|
+
exports.generateBlogCommentsCode = generateBlogCommentsCode;
|
|
34
|
+
//# sourceMappingURL=blog-comments.js.map
|