@teleporthq/teleport-project-plugin-parse-embed 0.27.9 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,96 @@
1
+ import { ComponentPlugin, ComponentPluginFactory, HastNode } from '@teleporthq/teleport-types'
2
+ import { UIDLUtils } from '@teleporthq/teleport-shared'
3
+ import { SUPPORTED_PROJECT_TYPES } from './utils'
4
+ import type { JSXElement, JSXIdentifier, JSXText } from '@babel/types'
5
+
6
+ interface ParseEmbedPluginConfig {
7
+ projectType: SUPPORTED_PROJECT_TYPES
8
+ }
9
+
10
+ const NODE_MAPPER: Record<
11
+ SUPPORTED_PROJECT_TYPES,
12
+ Promise<(content: unknown, options: unknown) => string>
13
+ > = {
14
+ html: import('hast-util-to-html').then((mod) => mod.toHtml),
15
+ jsx: import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
16
+ 'teleport-project-html': import('hast-util-to-html').then((mod) => mod.toHtml),
17
+ 'teleport-project-react': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
18
+ 'teleport-project-next': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
19
+ }
20
+
21
+ const COMPONENT_CHUNK_NAMES: Record<SUPPORTED_PROJECT_TYPES, string> = {
22
+ html: 'html-chunk',
23
+ jsx: 'jsx-component',
24
+ 'teleport-project-html': 'html-chunk',
25
+ 'teleport-project-next': 'jsx-component',
26
+ 'teleport-project-react': 'jsx-component',
27
+ }
28
+
29
+ export const createParseEmbedPlugin: ComponentPluginFactory<ParseEmbedPluginConfig> = (config) => {
30
+ const { projectType } = config
31
+
32
+ if (!NODE_MAPPER[projectType]) {
33
+ throw new Error(`Received a invalid ${projectType}`)
34
+ }
35
+
36
+ const componentPlugin: ComponentPlugin = async (structure) => {
37
+ const { uidl, chunks, dependencies } = structure
38
+ const compontnChunk = chunks.find((chunk) => chunk?.name === COMPONENT_CHUNK_NAMES[projectType])
39
+
40
+ if (!compontnChunk) {
41
+ throw new Error(`MIssing component chunk to parse for embeds`)
42
+ }
43
+
44
+ const fromHtml = (await import('hast-util-from-html')).fromHtml
45
+ const hastToJsxOrHtml = await NODE_MAPPER[projectType]
46
+
47
+ UIDLUtils.traverseElements(uidl.node, (element) => {
48
+ const { key, elementType, attrs } = element
49
+
50
+ if (
51
+ (elementType === 'dangerous-html' || element.dependency?.path === 'dangerous-html') &&
52
+ attrs?.html
53
+ ) {
54
+ const hastNodes = fromHtml(element.attrs.html.content as string, {
55
+ fragment: true,
56
+ })
57
+ const content = hastToJsxOrHtml(hastNodes, { wrapper: 'fragment' })
58
+
59
+ if (projectType === 'teleport-project-html' || projectType === 'html') {
60
+ const node = compontnChunk.meta.nodesLookup[key] as HastNode
61
+ if (!node) {
62
+ return
63
+ }
64
+ /*
65
+ Convert the HastNode to HastText
66
+ */
67
+
68
+ Object.assign(node, {
69
+ type: 'text',
70
+ value: content,
71
+ })
72
+
73
+ delete node.children
74
+ delete node.properties
75
+ delete dependencies['dangerous-html']
76
+ } else {
77
+ const node = compontnChunk.meta.nodesLookup[key] as JSXElement
78
+ if (!node) {
79
+ return
80
+ }
81
+ ;(node.openingElement.name as JSXIdentifier).name = 'React.Fragment'
82
+ ;(node.closingElement.name as JSXIdentifier).name = 'React.Fragment'
83
+ node.openingElement.attributes = []
84
+ node.children.push({
85
+ type: 'JSXText' as const,
86
+ value: content,
87
+ } as JSXText)
88
+ }
89
+ }
90
+ })
91
+
92
+ return structure
93
+ }
94
+
95
+ return componentPlugin
96
+ }
package/src/index.ts CHANGED
@@ -1,106 +1,31 @@
1
- import { UIDLUtils } from '@teleporthq/teleport-shared'
2
- import {
3
- ProjectPluginStructure,
4
- ProjectPlugin,
5
- UIDLElementNode,
6
- UIDLRootComponent,
7
- ComponentUIDL,
8
- } from '@teleporthq/teleport-types'
9
- import { JS_EXECUTION_DEPENDENCIES, SUPPORTED_PROJECT_TYPES } from './utils'
10
-
11
- const NODE_MAPPER: Record<SUPPORTED_PROJECT_TYPES, Promise<(content: unknown) => string>> = {
12
- 'teleport-project-html': import('hast-util-to-html').then((mod) => mod.toHtml),
13
- 'teleport-project-react': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
14
- 'teleport-project-next': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
15
- }
16
-
17
- export class ProjectPluginParseEmbed implements ProjectPlugin {
18
- fromHtml: (value: string, opts: { fragment: boolean }) => unknown
19
- hastToJsxOrHtml: (content: unknown, opts: { wrapper: string }) => string
20
-
21
- async loadFromHTML(): Promise<(value: string, opts: { fragment: boolean }) => unknown> {
22
- if (!this.fromHtml) {
23
- this.fromHtml = (await import('hast-util-from-html')).fromHtml
24
- }
25
- return this.fromHtml
26
- }
27
-
28
- async loadNodeMapper(
29
- id: SUPPORTED_PROJECT_TYPES
30
- ): Promise<(content: unknown, opts: { wrapper: string }) => string> {
31
- if (!this.hastToJsxOrHtml) {
32
- this.hastToJsxOrHtml = await NODE_MAPPER[id]
33
- }
34
- return this.hastToJsxOrHtml
35
- }
36
-
37
- async traverseComponentUIDL(node: UIDLElementNode, id: SUPPORTED_PROJECT_TYPES): Promise<void> {
38
- return new Promise((resolve, reject) => {
39
- try {
40
- UIDLUtils.traverseElements(node, (element) => {
41
- if (element.elementType === 'html-node' && element.attrs?.html && NODE_MAPPER[id]) {
42
- const hastNodes = this.fromHtml(element.attrs.html.content as string, {
43
- fragment: true,
44
- })
45
- const content = this.hastToJsxOrHtml(hastNodes, { wrapper: 'fragment' })
46
- element.elementType = 'container'
47
- element.attrs = {}
48
- element.style = { display: { type: 'static', content: 'contents' } }
49
- element.children = [
50
- {
51
- type: 'inject',
52
- content,
53
- ...(content.includes('<Script') && { dependency: JS_EXECUTION_DEPENDENCIES[id] }),
54
- },
55
- ]
56
- }
57
- })
58
- resolve()
59
- } catch (error) {
60
- reject(error)
61
- }
62
- })
63
- }
64
-
65
- async traverseNodeAndAddImport(
66
- componentUIDL: UIDLRootComponent | ComponentUIDL,
67
- projectType: SUPPORTED_PROJECT_TYPES
68
- ) {
69
- await this.traverseComponentUIDL(componentUIDL.node, projectType)
70
- }
1
+ import { ProjectPluginStructure, ProjectPlugin } from '@teleporthq/teleport-types'
2
+ import { createParseEmbedPlugin } from './component-plugin'
3
+ import { SUPPORTED_PROJECT_TYPES } from './utils'
71
4
 
5
+ class ProjectPluginParseEmbed implements ProjectPlugin {
72
6
  async runBefore(structure: ProjectPluginStructure) {
73
- await this.loadFromHTML()
74
- const projectType = structure.strategy.id as SUPPORTED_PROJECT_TYPES
75
- await this.loadNodeMapper(projectType)
7
+ const parseEmbedPlugin = createParseEmbedPlugin({
8
+ projectType: structure.strategy.id as SUPPORTED_PROJECT_TYPES,
9
+ })
76
10
 
77
- if (!NODE_MAPPER[projectType]) {
78
- return structure
11
+ if (structure.strategy.pages?.plugins?.length > 0) {
12
+ structure.strategy.pages.plugins.push(parseEmbedPlugin)
13
+ } else {
14
+ structure.strategy.pages.plugins = [parseEmbedPlugin]
79
15
  }
80
16
 
81
- const promises: Array<Promise<void>> = []
82
- promises.push(this.traverseNodeAndAddImport(structure.uidl.root, projectType))
83
-
84
- const components = Object.keys(structure.uidl?.components || {})
85
- for (let i = 0; i < components.length; i++) {
86
- promises.push(
87
- this.traverseNodeAndAddImport(structure.uidl.components[components[i]], projectType)
88
- )
17
+ if (structure.strategy.components?.plugins?.length > 0) {
18
+ structure.strategy.components.plugins.push(parseEmbedPlugin)
19
+ } else {
20
+ structure.strategy.components.plugins = [parseEmbedPlugin]
89
21
  }
90
22
 
91
- await Promise.all(promises)
92
23
  return structure
93
24
  }
94
25
 
95
26
  async runAfter(structure: ProjectPluginStructure) {
96
- if (!NODE_MAPPER[structure.strategy.id as SUPPORTED_PROJECT_TYPES]) {
97
- return structure
98
- }
99
-
100
- if (structure.strategy.id === 'teleport-project-react') {
101
- structure.dependencies['dangerous-html'] = '^0.1.13'
102
- }
103
-
104
27
  return structure
105
28
  }
106
29
  }
30
+
31
+ export { createParseEmbedPlugin, ProjectPluginParseEmbed }
package/src/utils.ts CHANGED
@@ -4,6 +4,8 @@ export type SUPPORTED_PROJECT_TYPES =
4
4
  | 'teleport-project-html'
5
5
  | 'teleport-project-react'
6
6
  | 'teleport-project-next'
7
+ | 'html'
8
+ | 'jsx'
7
9
 
8
10
  export const JS_EXECUTION_DEPENDENCIES: Record<string, UIDLExternalDependency> = {
9
11
  'teleport-project-react': {