fix: Xml namespaces support (#4351)

## Description

closes #4343

## Steps for reproduction


https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-sitemap.staging.webstudio.is/?pageId=FsnS9ui6btzM4W3YELE3Q&authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d


<img width="423" alt="image"
src="https://github.com/user-attachments/assets/711bbda5-cf92-4421-853b-23eddcb8a8a7">


Resulting xml

https://webstudio-fixture-project-a-0su3o.wstd.work/sitemap.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>https://webstudio-fixture-project-a-0su3o.wstd.work/</loc><lastmod>2024-05-07</lastmod><xhtml:link rel="alternate" hreflang="en" href="https://webstudio-fixture-project-a-0su3o.wstd.work/en"></xhtml:link></url><url><loc>https://webstudio-fixture-project-a-0su3o.wstd.work/olegs-test</loc><lastmod>2024-05-07</lastmod><xhtml:link rel="alternate" hreflang="en" href="https://webstudio-fixture-project-a-0su3o.wstd.work/olegs-testen"></xhtml:link></url><url><loc>custom-hand-made-location</loc><lastmod>2020-10-10</lastmod><xhtml:link rel="alternate" hreflang="en" href="custom-en-location"></xhtml:link></url></urlset>
```

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
5de6)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
This commit is contained in:
Ivan Starkov authored and GitHub committed 2024-10-28 23:09:13 +03:00
1 parent afc77fa72a
commit ab2a985451
9 files changed
+729 -48

No files matched your search

@@ -1,10 +1,10 @@
{
"build": {
"id": "6876de3a-942a-466b-9761-ad7cb2fa2c21",
"id": "1710e6a3-6f3b-44c9-8e4f-4176be77673e",
"projectId": "cddc1d44-af37-4cb6-a430-d300cf6f932d",
"version": 321,
"createdAt": "2024-10-08T17:47:04.557+00:00",
"updatedAt": "2024-10-08T17:47:04.557+00:00",
"version": 341,
"createdAt": "2024-10-28T17:19:04.754+00:00",
"updatedAt": "2024-10-28T17:19:04.754+00:00",
"pages": {
"meta": {
"siteName": "KittyGuardedZone",
@@ -155,6 +155,32 @@
"include": false
},
"path": "/class-names"
},
{
"id": "FsnS9ui6btzM4W3YELE3Q",
"name": "sitemap.xml",
"title": "\"Untitled\"",
"rootInstanceId": "z4Gp8noJpB4NS3JmdXh1Y",
"systemDataSourceId": "NB_R8mrrGxFXCCsAtL8QK",
"meta": {
"description": "\"\"",
"excludePageFromSearch": "true",
"language": "\"\"",
"socialImageUrl": "\"\"",
"status": "200",
"redirect": "\"\"",
"documentType": "xml",
"custom": [
{
"property": "",
"content": "\"\""
}
]
},
"marketplace": {
"include": false
},
"path": "/sitemap.xml"
}
],
"folders": [
@@ -171,7 +197,8 @@
"TS39WeBd0Qr3QgbSlzdf2",
"42cWhASQ3tTtKDnsvzhUF",
"9xlwLSHxuk8HmS3-EEGcf",
"lTS5DKrDEC_mXSAc5ZDDA"
"lTS5DKrDEC_mXSAc5ZDDA",
"FsnS9ui6btzM4W3YELE3Q"
]
},
{
@@ -1553,6 +1580,32 @@
"unit": "px"
}
}
],
[
"LnOCG1kkSViZaAVoz4GXw:UoTkWyaFuTYJihS3MFYK5:marginTop:",
{
"styleSourceId": "LnOCG1kkSViZaAVoz4GXw",
"breakpointId": "UoTkWyaFuTYJihS3MFYK5",
"property": "marginTop",
"value": {
"type": "unit",
"unit": "em",
"value": 1
}
}
],
[
"LnOCG1kkSViZaAVoz4GXw:UoTkWyaFuTYJihS3MFYK5:marginBottom:",
{
"styleSourceId": "LnOCG1kkSViZaAVoz4GXw",
"breakpointId": "UoTkWyaFuTYJihS3MFYK5",
"property": "marginBottom",
"value": {
"type": "unit",
"unit": "em",
"value": 0
}
}
]
],
"styleSources": [
@@ -1737,6 +1790,13 @@
"type": "local",
"id": "g6Z7dAxi6LYB-XtI6SaRR"
}
],
[
"LnOCG1kkSViZaAVoz4GXw",
{
"type": "local",
"id": "LnOCG1kkSViZaAVoz4GXw"
}
]
],
"styleSourceSelections": [
@@ -1921,6 +1981,13 @@
"instanceId": "T-rqx2b12pRrWcafRRoIG",
"values": ["g6Z7dAxi6LYB-XtI6SaRR"]
}
],
[
"LYBzzBvHLrfSOmPLs52dP",
{
"instanceId": "LYBzzBvHLrfSOmPLs52dP",
"values": ["LnOCG1kkSViZaAVoz4GXw"]
}
]
],
"props": [
@@ -2334,6 +2401,206 @@
"type": "expression",
"value": "`${$ws$dataSource$FG6camSaR89vSBREAV9PT} class_3`"
}
],
[
"flD2WGZT36p4CEaZOVFl6",
{
"id": "flD2WGZT36p4CEaZOVFl6",
"instanceId": "zJkrskDJhaEk-nOSRWrGg",
"name": "data",
"type": "expression",
"value": "[\n {\n \"path\": \"/\",\n \"lastModified\": \"2024-05-07\"\n },\n {\n \"path\": \"/olegs-test\",\n \"lastModified\": \"2024-05-07\"\n }\n]"
}
],
[
"4TLznPGh--A7PjsBOBxka",
{
"id": "4TLznPGh--A7PjsBOBxka",
"instanceId": "zJkrskDJhaEk-nOSRWrGg",
"name": "item",
"type": "parameter",
"value": "2pjBK-2keQ15QSbnjLOk1"
}
],
[
"NHtEMEG0kS-0V_RVLYG-S",
{
"id": "NHtEMEG0kS-0V_RVLYG-S",
"instanceId": "USgd2tJcA7pt-9xq4H4XP",
"name": "tag",
"type": "string",
"value": "url"
}
],
[
"xnnMp6L60pLHmdUgyanrg",
{
"id": "xnnMp6L60pLHmdUgyanrg",
"instanceId": "vw4jVDxlyJhw77jdG3lpd",
"name": "tag",
"type": "string",
"value": "loc"
}
],
[
"KnGNfGmPtiKrV2FNVkpaW",
{
"id": "KnGNfGmPtiKrV2FNVkpaW",
"instanceId": "zgwCRmVObvwI6a7zmD9OD",
"name": "tag",
"type": "string",
"value": "lastmod"
}
],
[
"2ec8PdWkJoKEehFI6knpl",
{
"id": "2ec8PdWkJoKEehFI6knpl",
"instanceId": "SVI6fI342JAxCvwsg4Oc6",
"name": "tag",
"type": "string",
"value": "urlset"
}
],
[
"z9yQBVKOIKgPCiMWHFNkx",
{
"id": "z9yQBVKOIKgPCiMWHFNkx",
"instanceId": "SVI6fI342JAxCvwsg4Oc6",
"name": "xmlns",
"type": "string",
"value": "http://www.sitemaps.org/schemas/sitemap/0.9"
}
],
[
"StcDsvZEgDu_30Lyl2F3G",
{
"id": "StcDsvZEgDu_30Lyl2F3G",
"instanceId": "8rjJjZTvM-WXjU8dVktBZ",
"name": "tag",
"type": "string",
"value": "url"
}
],
[
"PlgU3AVcOnqXiNtqNAqky",
{
"id": "PlgU3AVcOnqXiNtqNAqky",
"instanceId": "sDGB6PDQ9YABCdk9DKBmz",
"name": "tag",
"type": "string",
"value": "loc"
}
],
[
"r-V5MpdY0q8n-aSYi8RtT",
{
"id": "r-V5MpdY0q8n-aSYi8RtT",
"instanceId": "7Xcdw3QXZnp_Ehel6A6bI",
"name": "tag",
"type": "string",
"value": "lastmod"
}
],
[
"A8Wu7uH9OlQedZwv5-P7X",
{
"id": "A8Wu7uH9OlQedZwv5-P7X",
"instanceId": "LYBzzBvHLrfSOmPLs52dP",
"name": "tag",
"type": "string",
"value": "h3"
}
],
[
"K8Q0cGdTrOHzJ0WXutMae",
{
"id": "K8Q0cGdTrOHzJ0WXutMae",
"instanceId": "bBAE2vpcCLzlcin29wQYA",
"name": "tag",
"type": "string",
"value": "xhtml:link"
}
],
[
"HOGRU7ZXYeL11n6TtpKJo",
{
"id": "HOGRU7ZXYeL11n6TtpKJo",
"instanceId": "bBAE2vpcCLzlcin29wQYA",
"name": "rel",
"type": "string",
"value": "alternate"
}
],
[
"G-QTw79T_Q1w2oGjRWO0c",
{
"id": "G-QTw79T_Q1w2oGjRWO0c",
"instanceId": "bBAE2vpcCLzlcin29wQYA",
"name": "hreflang",
"type": "string",
"value": "en"
}
],
[
"Fpb7wkI2VjRdc03wTTNfo",
{
"id": "Fpb7wkI2VjRdc03wTTNfo",
"instanceId": "bBAE2vpcCLzlcin29wQYA",
"name": "href",
"type": "string",
"value": "custom-en-location"
}
],
[
"0AvNbmtwI9MjjfowIxYYh",
{
"id": "0AvNbmtwI9MjjfowIxYYh",
"instanceId": "yDQOMG0BUdvM5g5hDV7JP",
"name": "tag",
"type": "string",
"value": "xhtml:link"
}
],
[
"bIQ9oPI1NqjcPRnNELKdB",
{
"id": "bIQ9oPI1NqjcPRnNELKdB",
"instanceId": "yDQOMG0BUdvM5g5hDV7JP",
"name": "rel",
"type": "string",
"value": "alternate"
}
],
[
"sdbARDMZjIiaN1socbZbD",
{
"id": "sdbARDMZjIiaN1socbZbD",
"instanceId": "yDQOMG0BUdvM5g5hDV7JP",
"name": "hreflang",
"type": "string",
"value": "en"
}
],
[
"erBMakiSxs-TaKCWuCoiD",
{
"id": "erBMakiSxs-TaKCWuCoiD",
"instanceId": "yDQOMG0BUdvM5g5hDV7JP",
"name": "href",
"type": "expression",
"value": "`${$ws$dataSource$NB_R8mrrGxFXCCsAtL8QK.origin ?? '${ORIGIN}'}${$ws$dataSource$2pjBK__DASH__2keQ15QSbnjLOk1.path}en`"
}
],
[
"Pf6idCc5mNEGBLrdL_1yN",
{
"id": "Pf6idCc5mNEGBLrdL_1yN",
"instanceId": "SVI6fI342JAxCvwsg4Oc6",
"name": "xmlns:xhtml",
"type": "string",
"value": "http://www.w3.org/1999/xhtml"
}
]
],
"dataSources": [
@@ -2513,6 +2780,24 @@
"value": "varClass"
}
}
],
[
"NB_R8mrrGxFXCCsAtL8QK",
{
"type": "parameter",
"id": "NB_R8mrrGxFXCCsAtL8QK",
"scopeInstanceId": "z4Gp8noJpB4NS3JmdXh1Y",
"name": "system"
}
],
[
"2pjBK-2keQ15QSbnjLOk1",
{
"type": "parameter",
"id": "2pjBK-2keQ15QSbnjLOk1",
"scopeInstanceId": "zJkrskDJhaEk-nOSRWrGg",
"name": "url"
}
]
],
"resources": [
@@ -3656,6 +3941,189 @@
"component": "Box",
"children": []
}
],
[
"z4Gp8noJpB4NS3JmdXh1Y",
{
"type": "instance",
"id": "z4Gp8noJpB4NS3JmdXh1Y",
"component": "Body",
"children": [
{
"type": "id",
"value": "SVI6fI342JAxCvwsg4Oc6"
}
]
}
],
[
"SVI6fI342JAxCvwsg4Oc6",
{
"type": "instance",
"id": "SVI6fI342JAxCvwsg4Oc6",
"component": "XmlNode",
"children": [
{
"type": "id",
"value": "zJkrskDJhaEk-nOSRWrGg"
},
{
"type": "id",
"value": "LYBzzBvHLrfSOmPLs52dP"
},
{
"type": "id",
"value": "8rjJjZTvM-WXjU8dVktBZ"
}
]
}
],
[
"zJkrskDJhaEk-nOSRWrGg",
{
"type": "instance",
"id": "zJkrskDJhaEk-nOSRWrGg",
"component": "ws:collection",
"label": "urls",
"children": [
{
"type": "id",
"value": "USgd2tJcA7pt-9xq4H4XP"
}
]
}
],
[
"USgd2tJcA7pt-9xq4H4XP",
{
"type": "instance",
"id": "USgd2tJcA7pt-9xq4H4XP",
"component": "XmlNode",
"children": [
{
"type": "id",
"value": "vw4jVDxlyJhw77jdG3lpd"
},
{
"type": "id",
"value": "zgwCRmVObvwI6a7zmD9OD"
},
{
"type": "id",
"value": "yDQOMG0BUdvM5g5hDV7JP"
}
]
}
],
[
"vw4jVDxlyJhw77jdG3lpd",
{
"type": "instance",
"id": "vw4jVDxlyJhw77jdG3lpd",
"component": "XmlNode",
"children": [
{
"type": "expression",
"value": "`${$ws$dataSource$NB_R8mrrGxFXCCsAtL8QK.origin ?? '${ORIGIN}'}${$ws$dataSource$2pjBK__DASH__2keQ15QSbnjLOk1.path}`"
}
]
}
],
[
"zgwCRmVObvwI6a7zmD9OD",
{
"type": "instance",
"id": "zgwCRmVObvwI6a7zmD9OD",
"component": "XmlNode",
"children": [
{
"type": "expression",
"value": "$ws$dataSource$2pjBK__DASH__2keQ15QSbnjLOk1.lastModified"
}
]
}
],
[
"LYBzzBvHLrfSOmPLs52dP",
{
"type": "instance",
"id": "LYBzzBvHLrfSOmPLs52dP",
"component": "Heading",
"children": [
{
"type": "text",
"value": "Below is custom section"
}
]
}
],
[
"8rjJjZTvM-WXjU8dVktBZ",
{
"type": "instance",
"id": "8rjJjZTvM-WXjU8dVktBZ",
"component": "XmlNode",
"children": [
{
"type": "id",
"value": "sDGB6PDQ9YABCdk9DKBmz"
},
{
"type": "id",
"value": "7Xcdw3QXZnp_Ehel6A6bI"
},
{
"type": "id",
"value": "bBAE2vpcCLzlcin29wQYA"
}
]
}
],
[
"sDGB6PDQ9YABCdk9DKBmz",
{
"type": "instance",
"id": "sDGB6PDQ9YABCdk9DKBmz",
"component": "XmlNode",
"children": [
{
"type": "text",
"value": "custom-hand-made-location"
}
]
}
],
[
"7Xcdw3QXZnp_Ehel6A6bI",
{
"type": "instance",
"id": "7Xcdw3QXZnp_Ehel6A6bI",
"component": "XmlNode",
"children": [
{
"type": "text",
"value": "2020-10-10"
}
]
}
],
[
"bBAE2vpcCLzlcin29wQYA",
{
"type": "instance",
"id": "bBAE2vpcCLzlcin29wQYA",
"component": "XmlNode",
"children": []
}
],
[
"yDQOMG0BUdvM5g5hDV7JP",
{
"type": "instance",
"id": "yDQOMG0BUdvM5g5hDV7JP",
"component": "XmlNode",
"children": []
}
]
],
"deployment": {
@@ -3827,6 +4295,32 @@
"include": false
},
"path": "/class-names"
},
{
"id": "FsnS9ui6btzM4W3YELE3Q",
"name": "sitemap.xml",
"title": "\"Untitled\"",
"rootInstanceId": "z4Gp8noJpB4NS3JmdXh1Y",
"systemDataSourceId": "NB_R8mrrGxFXCCsAtL8QK",
"meta": {
"description": "\"\"",
"excludePageFromSearch": "true",
"language": "\"\"",
"socialImageUrl": "\"\"",
"status": "200",
"redirect": "\"\"",
"documentType": "xml",
"custom": [
{
"property": "",
"content": "\"\""
}
]
},
"marketplace": {
"include": false
},
"path": "/sitemap.xml"
}
],
"assets": [
@@ -1,26 +1,26 @@
export const sitemap = [
{
path: "/",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
{
path: "/_route_with_symbols_",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
{
path: "/form",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
{
path: "/heading-with-id",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
{
path: "/resources",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
{
path: "/nested/nested-page",
lastModified: "2024-10-08",
lastModified: "2024-10-28",
},
];
@@ -0,0 +1,39 @@
/* eslint-disable */
/* This is a auto generated file for building the project */
import type { PageMeta } from "@webstudio-is/sdk";
import type { System, ResourceRequest } from "@webstudio-is/sdk";
export const getResources = (_props: { system: System }) => {
const _data = new Map<string, ResourceRequest>([]);
const _action = new Map<string, ResourceRequest>([]);
return { data: _data, action: _action };
};
export const getPageMeta = ({
system,
resources,
}: {
system: System;
resources: Record<string, any>;
}): PageMeta => {
return {
title: "Untitled",
description: "",
excludePageFromSearch: true,
language: "",
socialImageAssetName: undefined,
socialImageUrl: "",
status: 200,
redirect: "",
custom: [],
};
};
type Params = Record<string, string | undefined>;
export const getRemixParams = ({ ...params }: Params): Params => {
return params;
};
export const projectId = "cddc1d44-af37-4cb6-a430-d300cf6f932d";
export const contactEmail = "hello@webstudio.is";
@@ -0,0 +1,82 @@
/* eslint-disable */
/* This is a auto generated file for building the project */
import { Fragment, useState } from "react";
import type { FontAsset, ImageAsset } from "@webstudio-is/sdk";
import { useResource, useVariableState } from "@webstudio-is/react-sdk/runtime";
import { XmlNode } from "@webstudio-is/sdk-components-react";
export const siteName = "KittyGuardedZone";
export const favIconAsset: ImageAsset | undefined = {
id: "88d5e2ff-b8f2-4899-aaf8-dde4ade6da10",
name: "DALL_E_2023-10-30_12.39.46_-_Photo_logo_with_a_bold_cat_silhouette_centered_on_a_contrasting_background_designed_for_clarity_at_small_32x32_favicon_resolution_00h6cEA8u2pJRvVJv7hRe.png",
description: null,
projectId: "cddc1d44-af37-4cb6-a430-d300cf6f932d",
size: 268326,
type: "image",
format: "png",
createdAt: "2023-10-30T13:51:08.416+00:00",
meta: { width: 790, height: 786 },
};
// Font assets on current page (can be preloaded)
export const pageFontAssets: FontAsset[] = [];
export const pageBackgroundImageAssets: ImageAsset[] = [];
const Body = (props: any) => props.children;
const Heading = (props: any) => null;
const Page = ({ system: system }: { system: any }) => {
return (
<Body className={"w-body"}>
<XmlNode
tag={"urlset"}
xmlns={"http://www.sitemaps.org/schemas/sitemap/0.9"}
xmlns:xhtml={"http://www.w3.org/1999/xhtml"}
>
{[
{
path: "/",
lastModified: "2024-05-07",
},
{
path: "/olegs-test",
lastModified: "2024-05-07",
},
]?.map((url: any, index: number) => (
<Fragment key={index}>
<XmlNode tag={"url"}>
<XmlNode tag={"loc"}>
{`${system?.origin ?? "${ORIGIN}"}${url?.path}`}
</XmlNode>
<XmlNode tag={"lastmod"}>{url?.lastModified}</XmlNode>
<XmlNode
tag={"xhtml:link"}
rel={"alternate"}
hreflang={"en"}
href={`${system?.origin ?? "${ORIGIN}"}${url?.path}en`}
/>
</XmlNode>
</Fragment>
))}
<Heading tag={"h3"} className={"w-heading c1jumvji cvdtpev"}>
{"Below is custom section"}
</Heading>
<XmlNode tag={"url"}>
<XmlNode tag={"loc"}>{"custom-hand-made-location"}</XmlNode>
<XmlNode tag={"lastmod"}>{"2020-10-10"}</XmlNode>
<XmlNode
tag={"xhtml:link"}
rel={"alternate"}
hreflang={"en"}
href={"custom-en-location"}
/>
</XmlNode>
</XmlNode>
</Body>
);
};
export { Page };
@@ -392,4 +392,10 @@
.ctm310 {
margin-top: 12px;
}
.c1jumvji {
margin-top: 1em;
}
.cvdtpev {
margin-bottom: 0em;
}
}
@@ -1,34 +1,79 @@
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { renderToString } from "react-dom/server";
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
import { isLocalResource, loadResources } from "@webstudio-is/sdk";
import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
import { Page } from "../__generated__/[sitemap.xml]._index";
import {
getPageMeta,
getRemixParams,
getResources,
} from "../__generated__/[sitemap.xml]._index.server";
import { assetBaseUrl, imageBaseUrl, imageLoader } from "../constants.mjs";
import { sitemap } from "../__generated__/$resources.sitemap.xml";
export const loader = (arg: LoaderFunctionArgs) => {
const customFetch: typeof fetch = (input, init) => {
if (typeof input !== "string") {
return fetch(input, init);
}
if (isLocalResource(input, "sitemap.xml")) {
// @todo: dynamic import sitemap ???
const response = new Response(JSON.stringify(sitemap));
response.headers.set("content-type", "application/json; charset=utf-8");
return Promise.resolve(response);
}
return fetch(input, init);
};
export const loader = async (arg: LoaderFunctionArgs) => {
const url = new URL(arg.request.url);
const host =
arg.request.headers.get("x-forwarded-host") ||
arg.request.headers.get("host") ||
"";
url.host = host;
url.protocol = "https";
const urls = sitemap.map((page) => {
const url = new URL(`https://${host}${page.path}`);
const params = getRemixParams(arg.params);
return `
<url>
<loc>${url.href}</loc>
<lastmod>${page.lastModified.split("T")[0]}</lastmod>
</url>
`;
});
const system = {
params,
search: Object.fromEntries(url.searchParams),
origin: url.origin,
};
return new Response(
`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.join("")}
</urlset>
`,
{
headers: {
"Content-Type": "application/xml",
},
status: 200,
}
const resources = await loadResources(
customFetch,
getResources({ system }).data
);
const pageMeta = getPageMeta({ system, resources });
if (pageMeta.redirect) {
const status =
pageMeta.status === 301 || pageMeta.status === 302
? pageMeta.status
: 302;
return redirect(pageMeta.redirect, status);
}
// typecheck
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;
const text = renderToString(
<ReactSdkContext.Provider
value={{
imageLoader,
assetBaseUrl,
imageBaseUrl,
resources,
}}
>
<Page system={system} />
</ReactSdkContext.Provider>
);
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
headers: { "Content-Type": "application/xml" },
});
};
+1 -1
View File
@@ -6,7 +6,7 @@
"typecheck": "tsc",
"cli": "NODE_OPTIONS='--conditions=webstudio --import=tsx' webstudio",
"fixtures:link": "pnpm cli link --link https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-${BUILDER_HOST:-main.development.webstudio.is}'?authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d'",
"fixtures:sync": "pnpm cli sync --buildId 6876de3a-942a-466b-9761-ad7cb2fa2c21 && pnpm prettier --write ./.webstudio/",
"fixtures:sync": "pnpm cli sync --buildId 1710e6a3-6f3b-44c9-8e4f-4176be77673e && pnpm prettier --write ./.webstudio/",
"fixtures:build": "pnpm cli build --template vercel --template internal --preview && pnpm prettier --write ./app/ ./package.json ./tsconfig.json"
},
"private": true,
+1 -1
View File
@@ -559,7 +559,7 @@ export const prebuild = async (options: {
.map((scopedName) =>
scopedName === "Body"
? `const ${scopedName} = (props: any) => props.children;`
: `const ${scopedName} = () => null;`
: `const ${scopedName} = (props: any) => null;`
)
.join("\n");
}
+27 -12
View File
@@ -14,7 +14,11 @@ export const defaultTag = "div";
type Props = {
tag: string;
xmlns?: string;
children: ReactNode;
children?: ReactNode;
rel?: string;
hreflang?: string;
href?: string;
"xmlns:xhtml"?: string;
};
export const XmlNode = forwardRef<ElementRef<"div">, Props>(
@@ -34,29 +38,40 @@ export const XmlNode = forwardRef<ElementRef<"div">, Props>(
return createElement(tag, attrProps, children);
}
const isTextChild = Children.toArray(children).every(
(child) => typeof child === "string"
);
const childrenArray = Children.toArray(children);
const isTextChild =
childrenArray.length > 0 &&
childrenArray.every((child) => typeof child === "string");
const elementName = tag
// Must start from letter or underscore
.replace(/^[^\p{L}_]+/u, "")
// Clear all non letter, number, underscore, dot, and dash
.replaceAll(/[^\p{L}\p{N}\-._]+/gu, "");
.replaceAll(/[^\p{L}\p{N}\-._:]+/gu, "");
const attributes = attributeEntries.map(
([key, value]) => `${key}=${JSON.stringify(value)}`
);
return (
<div style={{ display: isTextChild ? "flex" : "contents" }} {...props}>
<div style={{ color: "rgb(16, 23, 233)" }}>
<div {...props}>
<span style={{ color: "rgb(16, 23, 233)" }}>
&lt;{[elementName, ...attributes].join(" ")}&gt;
</div>
<div ref={ref} style={{ marginLeft: isTextChild ? 0 : "1rem" }}>
{children}
</div>
<div style={{ color: "rgb(16, 23, 233)" }}>&lt;/{elementName}&gt;</div>
</span>
{childrenArray.length > 0 && (
<div
ref={ref}
style={{
display: isTextChild ? "inline" : "block",
marginLeft: isTextChild ? 0 : "1rem",
}}
>
{children}
</div>
)}
<span style={{ color: "rgb(16, 23, 233)" }}>
&lt;/{elementName}&gt;
</span>
</div>
);
}