@teleporthq/teleport-project-plugin-parse-embed 0.34.0-alpha.0 → 0.34.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,103 @@
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
+ 'teleport-project-html': import('hast-util-to-html').then((mod) => mod.toHtml),
15
+ 'teleport-project-angular': import('hast-util-to-html').then((mod) => mod.toHtml),
16
+ 'teleport-project-vue': import('hast-util-to-html').then((mod) => mod.toHtml),
17
+ 'teleport-project-nuxt': import('hast-util-to-html').then((mod) => mod.toHtml),
18
+ 'teleport-project-react': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
19
+ 'teleport-project-next': import('hast-util-to-jsx-inline-script').then((mod) => mod.default),
20
+ }
21
+
22
+ const COMPONENT_CHUNK_NAMES: Record<SUPPORTED_PROJECT_TYPES, string> = {
23
+ 'teleport-project-html': 'html-chunk',
24
+ 'teleport-project-angular': 'template-chunk',
25
+ 'teleport-project-vue': 'template-chunk',
26
+ 'teleport-project-nuxt': 'template-chunk',
27
+ 'teleport-project-next': 'jsx-component',
28
+ 'teleport-project-react': 'jsx-component',
29
+ }
30
+
31
+ export const createParseEmbedPlugin: ComponentPluginFactory<ParseEmbedPluginConfig> = (config) => {
32
+ const { projectType } = config
33
+
34
+ if (!NODE_MAPPER[projectType]) {
35
+ throw new Error(`Received a invalid ${projectType}`)
36
+ }
37
+
38
+ const componentPlugin: ComponentPlugin = async (structure) => {
39
+ const { uidl, chunks, dependencies } = structure
40
+ const compontnChunk = chunks.find((chunk) => chunk?.name === COMPONENT_CHUNK_NAMES[projectType])
41
+
42
+ if (!compontnChunk) {
43
+ throw new Error(`MIssing component chunk to parse for embeds`)
44
+ }
45
+
46
+ const fromHtml = (await import('hast-util-from-html')).fromHtml
47
+ const hastToJsxOrHtml = await NODE_MAPPER[projectType]
48
+
49
+ UIDLUtils.traverseElements(uidl.node, (element) => {
50
+ const { key, elementType, attrs } = element
51
+
52
+ if (
53
+ (elementType === 'dangerous-html' || element.dependency?.path === 'dangerous-html') &&
54
+ attrs?.html
55
+ ) {
56
+ const hastNodes = fromHtml(element.attrs.html.content as string, {
57
+ fragment: true,
58
+ })
59
+ const content = hastToJsxOrHtml(hastNodes, { wrapper: 'fragment' })
60
+
61
+ if (
62
+ projectType === 'teleport-project-html' ||
63
+ projectType === 'teleport-project-angular' ||
64
+ projectType === 'teleport-project-vue' ||
65
+ projectType === 'teleport-project-nuxt'
66
+ ) {
67
+ const node = compontnChunk.meta.nodesLookup[key] as HastNode
68
+ if (!node) {
69
+ return
70
+ }
71
+ /*
72
+ Convert the HastNode to HastText
73
+ */
74
+
75
+ Object.assign(node, {
76
+ type: 'text',
77
+ value: content,
78
+ })
79
+
80
+ delete node.children
81
+ delete node.properties
82
+ delete dependencies['dangerous-html']
83
+ } else {
84
+ const node = compontnChunk.meta.nodesLookup[key] as JSXElement
85
+ if (!node) {
86
+ return
87
+ }
88
+ ;(node.openingElement.name as JSXIdentifier).name = 'React.Fragment'
89
+ ;(node.closingElement.name as JSXIdentifier).name = 'React.Fragment'
90
+ node.openingElement.attributes = []
91
+ node.children.push({
92
+ type: 'JSXText' as const,
93
+ value: content,
94
+ } as JSXText)
95
+ }
96
+ }
97
+ })
98
+
99
+ return structure
100
+ }
101
+
102
+ return componentPlugin
103
+ }
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,9 @@ export type SUPPORTED_PROJECT_TYPES =
4
4
  | 'teleport-project-html'
5
5
  | 'teleport-project-react'
6
6
  | 'teleport-project-next'
7
+ | 'teleport-project-angular'
8
+ | 'teleport-project-vue'
9
+ | 'teleport-project-nuxt'
7
10
 
8
11
  export const JS_EXECUTION_DEPENDENCIES: Record<string, UIDLExternalDependency> = {
9
12
  'teleport-project-react': {