@teleporthq/teleport-plugin-html-base-component
Advanced tools
Comparing version 0.31.0-alpha.0 to 0.31.0
@@ -11,13 +11,13 @@ import { | ||
const getMockComponentStructure: ComponentStructure = () => ({ | ||
chunks: [], | ||
options: {}, | ||
uidl: component('Test', elementNode('container')), | ||
dependencies: {}, | ||
}) | ||
describe('plugin-html-base-component', () => { | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const structure: ComponentStructure = { | ||
chunks: [], | ||
options: {}, | ||
uidl: component('Test', elementNode('container')), | ||
dependencies: {}, | ||
} | ||
it('generated HAST nodes with the UIDL that is passed', async () => { | ||
const { chunks } = await htmlComponentPlugin(structure) | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const { chunks } = await htmlComponentPlugin(getMockComponentStructure()) | ||
const htmlChunk = chunks.find((chunk) => chunk.fileType === FileType.HTML) | ||
@@ -27,8 +27,9 @@ | ||
expect(htmlChunk).toBeDefined() | ||
expect(htmlChunk.name).toBe('html-template') | ||
expect(htmlChunk.name).toBe('html-chunk') | ||
}) | ||
it('adds attributes to the HAST node', async () => { | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const { chunks } = await htmlComponentPlugin({ | ||
...structure, | ||
...getMockComponentStructure(), | ||
uidl: component( | ||
@@ -42,4 +43,4 @@ 'Test', | ||
expect(chunks.length).toEqual(2) | ||
expect(((chunks[1].content as HastNode).children[0] as HastNode).properties.href).toBe( | ||
expect(chunks.length).toEqual(1) | ||
expect(((chunks[0].content as HastNode).children[0] as HastNode).properties.href).toBe( | ||
'about.html' | ||
@@ -50,14 +51,16 @@ ) | ||
it('wraps static content inside div tags', async () => { | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const { chunks } = await htmlComponentPlugin({ | ||
...structure, | ||
...getMockComponentStructure(), | ||
uidl: component('Test', staticNode('Hello') as unknown as UIDLElementNode), | ||
}) | ||
expect(chunks.length).toEqual(3) | ||
expect((chunks[2].content as HastNode).children.length).toEqual(1) | ||
expect(chunks.length).toEqual(1) | ||
expect((chunks[0].content as HastNode).children.length).toEqual(1) | ||
}) | ||
it('Throws error when a external comp is missing', async () => { | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const plugin = htmlComponentPlugin({ | ||
...structure, | ||
...getMockComponentStructure(), | ||
uidl: component('Test', elementNode('Sample', {}, [], { type: 'local' })), | ||
@@ -70,4 +73,5 @@ }) | ||
it('Takes default value from props and state, when nodes are using dynamic ref', async () => { | ||
const { htmlComponentPlugin } = createHTMLBasePlugin() | ||
const { chunks } = await htmlComponentPlugin({ | ||
...structure, | ||
...getMockComponentStructure(), | ||
uidl: component('Test', elementNode('container', {}, [dynamicNode('prop', 'content')]), { | ||
@@ -79,6 +83,6 @@ content: { type: 'string', defaultValue: 'Hello World' }, | ||
const hastText = ( | ||
((chunks[3].content as HastNode).children[0] as HastNode).children[0] as HastNode | ||
((chunks[0].content as HastNode).children[0] as HastNode).children[0] as HastNode | ||
).children[0] as HastText | ||
expect(chunks.length).toEqual(4) | ||
expect(chunks.length).toEqual(1) | ||
expect(hastText).toBeDefined() | ||
@@ -85,0 +89,0 @@ expect(hastText.type).toBe('text') |
@@ -1,2 +0,2 @@ | ||
export declare const DEFAULT_COMPONENT_CHUNK_NAME = "html-template"; | ||
export declare const DEFAULT_COMPONENT_CHUNK_NAME = "html-chunk"; | ||
//# sourceMappingURL=constants.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DEFAULT_COMPONENT_CHUNK_NAME = void 0; | ||
exports.DEFAULT_COMPONENT_CHUNK_NAME = 'html-template'; | ||
exports.DEFAULT_COMPONENT_CHUNK_NAME = 'html-chunk'; | ||
//# sourceMappingURL=constants.js.map |
@@ -8,5 +8,5 @@ import { ComponentPlugin, ComponentDefaultPluginParams, ComponentUIDL } from '@teleporthq/teleport-types'; | ||
htmlComponentPlugin: ComponentPlugin; | ||
addExternals: (list: Record<string, ComponentUIDL>) => void; | ||
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void; | ||
} | ||
declare type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin; | ||
type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin; | ||
export declare const createHTMLBasePlugin: HtmlPluginFactory<HtmlPluginConfig>; | ||
@@ -13,0 +13,0 @@ declare const _default: HtmlPlugin; |
@@ -28,3 +28,3 @@ "use strict"; | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
@@ -60,12 +60,15 @@ if (y = 0, t) op = [op[0] & 2, t.value]; | ||
var externals = {}; | ||
var addExternals = function (list) { | ||
var plugins = []; | ||
var addExternals = function (list, subComponentPlugins) { | ||
if (subComponentPlugins === void 0) { subComponentPlugins = []; } | ||
externals = __assign(__assign({}, externals), (list || {})); | ||
plugins = subComponentPlugins; | ||
}; | ||
var htmlComponentPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var uidl, chunks, dependencies, options, _a, propDefinitions, _b, stateDefinitions, templatesLookUp, compBase, bodyContent; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var uidl, _a, chunks, dependencies, options, _b, propDefinitions, _c, stateDefinitions, outputOptions, templatesLookUp, compBase, bodyContent; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options; | ||
_a = uidl.propDefinitions, propDefinitions = _a === void 0 ? {} : _a, _b = uidl.stateDefinitions, stateDefinitions = _b === void 0 ? {} : _b; | ||
uidl = structure.uidl, _a = structure.chunks, chunks = _a === void 0 ? [] : _a, dependencies = structure.dependencies, options = structure.options; | ||
_b = uidl.propDefinitions, propDefinitions = _b === void 0 ? {} : _b, _c = uidl.stateDefinitions, stateDefinitions = _c === void 0 ? {} : _c, outputOptions = uidl.outputOptions; | ||
templatesLookUp = {}; | ||
@@ -75,11 +78,14 @@ compBase = wrapComponent | ||
: teleport_plugin_common_1.HASTBuilders.createHTMLNode('div'); | ||
return [4 /*yield*/, (0, node_handlers_1.generateHtmlSynatx)(uidl.node, templatesLookUp, propDefinitions, stateDefinitions, Object.values(externals).reduce(function (acc, comp) { | ||
teleport_shared_1.UIDLUtils.setFriendlyOutputOptions(comp); | ||
comp.name = teleport_shared_1.StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent'; | ||
comp.name = teleport_shared_1.UIDLUtils.getComponentClassName(comp); | ||
acc[comp.name] = comp; | ||
return acc; | ||
}, {}), options.projectRouteDefinition, { chunks: chunks, dependencies: dependencies, options: options })]; | ||
return [4 /*yield*/, (0, node_handlers_1.generateHtmlSynatx)(uidl.node, templatesLookUp, propDefinitions, stateDefinitions, { | ||
externals: Object.values(externals).reduce(function (acc, comp) { | ||
teleport_shared_1.UIDLUtils.setFriendlyOutputOptions(comp); | ||
comp.name = teleport_shared_1.StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent'; | ||
comp.name = teleport_shared_1.UIDLUtils.getComponentClassName(comp); | ||
acc[comp.name] = comp; | ||
return acc; | ||
}, {}), | ||
plugins: plugins, | ||
}, { chunks: chunks, dependencies: dependencies, options: options, outputOptions: outputOptions })]; | ||
case 1: | ||
bodyContent = _c.sent(); | ||
bodyContent = _d.sent(); | ||
teleport_plugin_common_1.HASTUtils.addChildNode(compBase, bodyContent); | ||
@@ -86,0 +92,0 @@ chunks.push({ |
@@ -1,6 +0,10 @@ | ||
import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, UIDLRouteDefinitions } from '@teleporthq/teleport-types'; | ||
declare type NodeToHTML<NodeType, ReturnType> = (node: NodeType, templatesLookUp: Record<string, unknown>, propDefinitions: Record<string, UIDLPropDefinition>, stateDefinitions: Record<string, UIDLStateDefinition>, externals: Record<string, ComponentUIDL>, routeDefinitions: UIDLRouteDefinitions, structure: { | ||
import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, ComponentPlugin, UIDLComponentOutputOptions } from '@teleporthq/teleport-types'; | ||
type NodeToHTML<NodeType, ReturnType> = (node: NodeType, templatesLookUp: Record<string, unknown>, propDefinitions: Record<string, UIDLPropDefinition>, stateDefinitions: Record<string, UIDLStateDefinition>, subComponentOptions: { | ||
externals: Record<string, ComponentUIDL>; | ||
plugins: ComponentPlugin[]; | ||
}, structure: { | ||
chunks: ChunkDefinition[]; | ||
dependencies: Record<string, UIDLDependency>; | ||
options: GeneratorOptions; | ||
outputOptions: UIDLComponentOutputOptions; | ||
}) => ReturnType; | ||
@@ -7,0 +11,0 @@ export declare const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>; |
@@ -28,3 +28,3 @@ "use strict"; | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
@@ -62,2 +62,3 @@ if (y = 0, t) op = [op[0] & 2, t.value]; | ||
var teleport_types_1 = require("@teleporthq/teleport-types"); | ||
var path_1 = require("path"); | ||
var teleport_plugin_common_1 = require("@teleporthq/teleport-plugin-common"); | ||
@@ -68,5 +69,16 @@ var teleport_shared_1 = require("@teleporthq/teleport-shared"); | ||
var constants_1 = require("./constants"); | ||
var generateHtmlSynatx = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var isValidURL = function (url) { | ||
try { | ||
/* tslint:disable:no-unused-expression */ | ||
new URL(url); | ||
return true; | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
}; | ||
var generateHtmlSynatx = function (node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (node.type) { | ||
case 'inject': | ||
case 'raw': | ||
@@ -79,5 +91,5 @@ return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createTextNode(node.content.toString())]; | ||
case 'element': | ||
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 'dynamic': | ||
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
default: | ||
@@ -90,3 +102,3 @@ throw new teleport_types_1.HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " ")); | ||
exports.generateHtmlSynatx = generateHtmlSynatx; | ||
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, elementType, children, _b, attrs, _c, style, _d, referencedStyles, dependency, key, elementNode, dependencies, compTag, _i, children_1, child, childTag; | ||
@@ -104,3 +116,3 @@ return __generator(this, function (_e) { | ||
if (!(dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) === 'local')) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, generateComponentContent(node, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [4 /*yield*/, generateComponentContent(node, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 1: | ||
@@ -116,3 +128,3 @@ compTag = _e.sent(); | ||
child = children_1[_i]; | ||
return [4 /*yield*/, (0, exports.generateHtmlSynatx)(child, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [4 /*yield*/, (0, exports.generateHtmlSynatx)(child, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 4: | ||
@@ -147,3 +159,3 @@ childTag = _e.sent(); | ||
if (Object.keys(attrs).length > 0) { | ||
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions); | ||
handleAttributes(elementType, elementNode, attrs, propDefinitions, stateDefinitions, structure.options.projectRouteDefinition, structure.outputOptions); | ||
} | ||
@@ -154,10 +166,11 @@ return [2 /*return*/, elementNode]; | ||
}); }; | ||
var generateComponentContent = function (node, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, elementType, _b, attrs, key, _c, children, dependencies, chunks, options, comp, lookUpTemplates, compHasSlots, combinedProps, propsForInstance, combinedStates, statesForInstance, elementNode, compTag, cssPlugin, result, chunk, styleChunk; | ||
var _d; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
var generateComponentContent = function (node, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var externals, plugins, _a, elementType, _b, attrs, key, _c, children, dependencies, _d, chunks, options, comp, lookUpTemplates, compHasSlots, combinedProps, propsForInstance, combinedStates, statesForInstance, elementNode, compTag, cssPlugin, initialStructure, result, chunk, styleChunk; | ||
var _e; | ||
return __generator(this, function (_f) { | ||
switch (_f.label) { | ||
case 0: | ||
externals = subComponentOptions.externals, plugins = subComponentOptions.plugins; | ||
_a = node.content, elementType = _a.elementType, _b = _a.attrs, attrs = _b === void 0 ? {} : _b, key = _a.key, _c = _a.children, children = _c === void 0 ? [] : _c; | ||
dependencies = structure.dependencies, chunks = structure.chunks, options = structure.options; | ||
dependencies = structure.dependencies, _d = structure.chunks, chunks = _d === void 0 ? [] : _d, options = structure.options; | ||
comp = teleport_shared_1.UIDLUtils.cloneObject(externals[elementType] || {}); | ||
@@ -223,11 +236,11 @@ lookUpTemplates = {}; | ||
lookUpTemplates[key] = elementNode; | ||
return [4 /*yield*/, (0, exports.generateHtmlSynatx)(__assign(__assign({}, comp.node), { content: __assign(__assign({}, comp.node.content), { style: __assign(__assign({}, (((_d = comp.node.content) === null || _d === void 0 ? void 0 : _d.style) || {})), { display: { | ||
return [4 /*yield*/, (0, exports.generateHtmlSynatx)(__assign(__assign({}, comp.node), { content: __assign(__assign({}, comp.node.content), { style: __assign(__assign({}, (((_e = comp.node.content) === null || _e === void 0 ? void 0 : _e.style) || {})), { display: { | ||
type: 'static', | ||
content: 'contents', | ||
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, externals, routeDefinitions, structure)]; | ||
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, subComponentOptions, structure)]; | ||
case 1: | ||
compTag = (_e.sent()); | ||
compTag = (_f.sent()); | ||
cssPlugin = (0, teleport_plugin_css_1.createCSSPlugin)({ | ||
templateStyle: 'html', | ||
templateChunkName: 'html-template', | ||
templateChunkName: constants_1.DEFAULT_COMPONENT_CHUNK_NAME, | ||
declareDependency: 'import', | ||
@@ -238,21 +251,32 @@ forceScoping: true, | ||
}); | ||
return [4 /*yield*/, cssPlugin({ | ||
uidl: __assign(__assign({}, comp), { propDefinitions: propsForInstance, stateDefinitions: statesForInstance }), | ||
chunks: [ | ||
{ | ||
type: teleport_types_1.ChunkType.HAST, | ||
fileType: teleport_types_1.FileType.HTML, | ||
name: constants_1.DEFAULT_COMPONENT_CHUNK_NAME, | ||
linkAfter: [], | ||
content: compTag, | ||
meta: { | ||
nodesLookup: lookUpTemplates, | ||
}, | ||
initialStructure = { | ||
uidl: __assign(__assign({}, comp), { propDefinitions: propsForInstance, stateDefinitions: statesForInstance }), | ||
chunks: [ | ||
{ | ||
type: teleport_types_1.ChunkType.HAST, | ||
fileType: teleport_types_1.FileType.HTML, | ||
name: constants_1.DEFAULT_COMPONENT_CHUNK_NAME, | ||
linkAfter: [], | ||
content: compTag, | ||
meta: { | ||
nodesLookup: lookUpTemplates, | ||
}, | ||
], | ||
dependencies: dependencies, | ||
options: options, | ||
})]; | ||
}, | ||
], | ||
dependencies: dependencies, | ||
options: options, | ||
}; | ||
return [4 /*yield*/, __spreadArray([cssPlugin], plugins, true).reduce(function (previousPluginOperation, plugin) { return __awaiter(void 0, void 0, void 0, function () { | ||
var modifiedStructure; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, previousPluginOperation]; | ||
case 1: | ||
modifiedStructure = _a.sent(); | ||
return [2 /*return*/, plugin(modifiedStructure)]; | ||
} | ||
}); | ||
}); }, Promise.resolve(initialStructure))]; | ||
case 2: | ||
result = _e.sent(); | ||
result = _f.sent(); | ||
if (compHasSlots) { | ||
@@ -268,3 +292,6 @@ result.chunks.forEach(function (chunk) { | ||
if (!chunk) { | ||
styleChunk = result.chunks.find(function (item) { return item.name === comp.name; }); | ||
styleChunk = result.chunks.find(function (item) { return item.fileType === teleport_types_1.FileType.CSS; }); | ||
if (!styleChunk) { | ||
return [2 /*return*/]; | ||
} | ||
chunks.push(styleChunk); | ||
@@ -300,3 +327,3 @@ } | ||
}; | ||
var handleAttributes = function (htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions) { | ||
var handleAttributes = function (elementType, htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions, outputOptions) { | ||
Object.keys(attrs).forEach(function (attrKey) { | ||
@@ -308,9 +335,16 @@ var attrValue = attrs[attrKey]; | ||
attrValue.content.startsWith('/')) { | ||
attrValue = | ||
attrValue.content === '/' || | ||
attrValue.content === | ||
"/".concat(teleport_shared_1.StringUtils.camelCaseToDashCase(teleport_shared_1.StringUtils.removeIllegalCharacters((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.defaultValue) || ''))) | ||
? (0, teleport_uidl_builders_1.staticNode)('index.html') | ||
: (0, teleport_uidl_builders_1.staticNode)("".concat(attrValue.content.split('/').pop(), ".html")); | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)); | ||
var targetLink = void 0; | ||
var targetRoute = ((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.values) || []).find(function (route) { return route.pageOptions.navLink === attrValue.content; }); | ||
if (targetRoute) { | ||
targetLink = targetRoute.pageOptions.navLink; | ||
} | ||
if (!targetRoute && attrValue.content === '/home') { | ||
targetLink = '/'; | ||
} | ||
if (!targetLink && !targetRoute) { | ||
targetLink = attrValue.content; | ||
} | ||
var currentPageRoute = path_1.join.apply(void 0, __spreadArray(__spreadArray([], ((outputOptions === null || outputOptions === void 0 ? void 0 : outputOptions.folderPath) || []), false), ['./'], false)); | ||
var localPrefix = (0, path_1.relative)("/".concat(currentPageRoute), "/".concat(targetLink === '/' ? 'index' : targetLink)); | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, "".concat(localPrefix, ".html")); | ||
return; | ||
@@ -326,3 +360,3 @@ } | ||
if (attrValue.type === 'raw') { | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)); | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content); | ||
return; | ||
@@ -335,3 +369,29 @@ } | ||
else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') { | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, teleport_shared_1.StringUtils.encode(String(attrValue.content))); | ||
var value = teleport_shared_1.StringUtils.encode(String(attrValue.content)); | ||
/* | ||
elementType of image is always mapped to img. | ||
For reference, check `html-mapping` file. | ||
*/ | ||
if (elementType === 'img' && attrKey === 'src' && !isValidURL(value)) { | ||
/* | ||
By default we just prefix all the asset paths with just the | ||
assetPrefix that is configured in the project. But for `html` generators | ||
we need to prefix that with the current file location. | ||
Because, all the other frameworks have a build setup. which serves all the | ||
assets from the `public` folder. But in the case of `html` here is how it works | ||
We load a file from `index.html` the request for the image goes from | ||
'...url.../public/...image...' | ||
If it's a nested url, then the request goes from | ||
'...url/nested/public/...image..' | ||
But the nested folder is available only on the root. With this | ||
The url changes prefixes to | ||
../public/playground_assets/..image.. etc depending on the dept the file is in. | ||
*/ | ||
value = (0, path_1.join)((0, path_1.relative)(path_1.join.apply(void 0, outputOptions.folderPath), './'), value); | ||
} | ||
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, value); | ||
return; | ||
@@ -342,3 +402,3 @@ } | ||
var getValueFromReference = function (key, definitions) { | ||
var usedReferenceValue = definitions[key]; | ||
var usedReferenceValue = definitions[key.includes('.') ? key.split('.')[0] : key]; | ||
if (!usedReferenceValue) { | ||
@@ -350,3 +410,3 @@ throw new teleport_types_1.HTMLComponentGeneratorError("Definition for ".concat(key, " is missing from ").concat(JSON.stringify(definitions, null, 2))); | ||
} | ||
if (!['string', 'number'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type)) { | ||
if (!['string', 'number', 'object'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type)) { | ||
throw new teleport_types_1.HTMLComponentGeneratorError("Attribute is using dynamic value, but received of type ".concat(JSON.stringify(usedReferenceValue, null, 2))); | ||
@@ -353,0 +413,0 @@ } |
@@ -1,2 +0,2 @@ | ||
export declare const DEFAULT_COMPONENT_CHUNK_NAME = "html-template"; | ||
export declare const DEFAULT_COMPONENT_CHUNK_NAME = "html-chunk"; | ||
//# sourceMappingURL=constants.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export var DEFAULT_COMPONENT_CHUNK_NAME = 'html-template'; | ||
export var DEFAULT_COMPONENT_CHUNK_NAME = 'html-chunk'; | ||
//# sourceMappingURL=constants.js.map |
@@ -8,5 +8,5 @@ import { ComponentPlugin, ComponentDefaultPluginParams, ComponentUIDL } from '@teleporthq/teleport-types'; | ||
htmlComponentPlugin: ComponentPlugin; | ||
addExternals: (list: Record<string, ComponentUIDL>) => void; | ||
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void; | ||
} | ||
declare type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin; | ||
type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin; | ||
export declare const createHTMLBasePlugin: HtmlPluginFactory<HtmlPluginConfig>; | ||
@@ -13,0 +13,0 @@ declare const _default: HtmlPlugin; |
@@ -27,3 +27,3 @@ var __assign = (this && this.__assign) || function () { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
@@ -57,12 +57,15 @@ if (y = 0, t) op = [op[0] & 2, t.value]; | ||
var externals = {}; | ||
var addExternals = function (list) { | ||
var plugins = []; | ||
var addExternals = function (list, subComponentPlugins) { | ||
if (subComponentPlugins === void 0) { subComponentPlugins = []; } | ||
externals = __assign(__assign({}, externals), (list || {})); | ||
plugins = subComponentPlugins; | ||
}; | ||
var htmlComponentPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var uidl, chunks, dependencies, options, _a, propDefinitions, _b, stateDefinitions, templatesLookUp, compBase, bodyContent; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var uidl, _a, chunks, dependencies, options, _b, propDefinitions, _c, stateDefinitions, outputOptions, templatesLookUp, compBase, bodyContent; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options; | ||
_a = uidl.propDefinitions, propDefinitions = _a === void 0 ? {} : _a, _b = uidl.stateDefinitions, stateDefinitions = _b === void 0 ? {} : _b; | ||
uidl = structure.uidl, _a = structure.chunks, chunks = _a === void 0 ? [] : _a, dependencies = structure.dependencies, options = structure.options; | ||
_b = uidl.propDefinitions, propDefinitions = _b === void 0 ? {} : _b, _c = uidl.stateDefinitions, stateDefinitions = _c === void 0 ? {} : _c, outputOptions = uidl.outputOptions; | ||
templatesLookUp = {}; | ||
@@ -72,11 +75,14 @@ compBase = wrapComponent | ||
: HASTBuilders.createHTMLNode('div'); | ||
return [4 /*yield*/, generateHtmlSynatx(uidl.node, templatesLookUp, propDefinitions, stateDefinitions, Object.values(externals).reduce(function (acc, comp) { | ||
UIDLUtils.setFriendlyOutputOptions(comp); | ||
comp.name = StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent'; | ||
comp.name = UIDLUtils.getComponentClassName(comp); | ||
acc[comp.name] = comp; | ||
return acc; | ||
}, {}), options.projectRouteDefinition, { chunks: chunks, dependencies: dependencies, options: options })]; | ||
return [4 /*yield*/, generateHtmlSynatx(uidl.node, templatesLookUp, propDefinitions, stateDefinitions, { | ||
externals: Object.values(externals).reduce(function (acc, comp) { | ||
UIDLUtils.setFriendlyOutputOptions(comp); | ||
comp.name = StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent'; | ||
comp.name = UIDLUtils.getComponentClassName(comp); | ||
acc[comp.name] = comp; | ||
return acc; | ||
}, {}), | ||
plugins: plugins, | ||
}, { chunks: chunks, dependencies: dependencies, options: options, outputOptions: outputOptions })]; | ||
case 1: | ||
bodyContent = _c.sent(); | ||
bodyContent = _d.sent(); | ||
HASTUtils.addChildNode(compBase, bodyContent); | ||
@@ -83,0 +89,0 @@ chunks.push({ |
@@ -1,6 +0,10 @@ | ||
import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, UIDLRouteDefinitions } from '@teleporthq/teleport-types'; | ||
declare type NodeToHTML<NodeType, ReturnType> = (node: NodeType, templatesLookUp: Record<string, unknown>, propDefinitions: Record<string, UIDLPropDefinition>, stateDefinitions: Record<string, UIDLStateDefinition>, externals: Record<string, ComponentUIDL>, routeDefinitions: UIDLRouteDefinitions, structure: { | ||
import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, ComponentPlugin, UIDLComponentOutputOptions } from '@teleporthq/teleport-types'; | ||
type NodeToHTML<NodeType, ReturnType> = (node: NodeType, templatesLookUp: Record<string, unknown>, propDefinitions: Record<string, UIDLPropDefinition>, stateDefinitions: Record<string, UIDLStateDefinition>, subComponentOptions: { | ||
externals: Record<string, ComponentUIDL>; | ||
plugins: ComponentPlugin[]; | ||
}, structure: { | ||
chunks: ChunkDefinition[]; | ||
dependencies: Record<string, UIDLDependency>; | ||
options: GeneratorOptions; | ||
outputOptions: UIDLComponentOutputOptions; | ||
}) => ReturnType; | ||
@@ -7,0 +11,0 @@ export declare const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>; |
@@ -27,3 +27,3 @@ var __assign = (this && this.__assign) || function () { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
@@ -59,2 +59,3 @@ if (y = 0, t) op = [op[0] & 2, t.value]; | ||
import { HTMLComponentGeneratorError, ChunkType, FileType, } from '@teleporthq/teleport-types'; | ||
import { join, relative } from 'path'; | ||
import { HASTBuilders, HASTUtils } from '@teleporthq/teleport-plugin-common'; | ||
@@ -65,5 +66,16 @@ import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'; | ||
import { DEFAULT_COMPONENT_CHUNK_NAME } from './constants'; | ||
export var generateHtmlSynatx = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var isValidURL = function (url) { | ||
try { | ||
/* tslint:disable:no-unused-expression */ | ||
new URL(url); | ||
return true; | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
}; | ||
export var generateHtmlSynatx = function (node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (node.type) { | ||
case 'inject': | ||
case 'raw': | ||
@@ -76,5 +88,5 @@ return [2 /*return*/, HASTBuilders.createTextNode(node.content.toString())]; | ||
case 'element': | ||
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 'dynamic': | ||
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
default: | ||
@@ -86,3 +98,3 @@ throw new HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " ")); | ||
}); }; | ||
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, elementType, children, _b, attrs, _c, style, _d, referencedStyles, dependency, key, elementNode, dependencies, compTag, _i, children_1, child, childTag; | ||
@@ -100,3 +112,3 @@ return __generator(this, function (_e) { | ||
if (!(dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) === 'local')) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, generateComponentContent(node, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [4 /*yield*/, generateComponentContent(node, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 1: | ||
@@ -112,3 +124,3 @@ compTag = _e.sent(); | ||
child = children_1[_i]; | ||
return [4 /*yield*/, generateHtmlSynatx(child, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)]; | ||
return [4 /*yield*/, generateHtmlSynatx(child, templatesLookUp, propDefinitions, stateDefinitions, subComponentOptions, structure)]; | ||
case 4: | ||
@@ -143,3 +155,3 @@ childTag = _e.sent(); | ||
if (Object.keys(attrs).length > 0) { | ||
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions); | ||
handleAttributes(elementType, elementNode, attrs, propDefinitions, stateDefinitions, structure.options.projectRouteDefinition, structure.outputOptions); | ||
} | ||
@@ -150,10 +162,11 @@ return [2 /*return*/, elementNode]; | ||
}); }; | ||
var generateComponentContent = function (node, propDefinitions, stateDefinitions, externals, routeDefinitions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, elementType, _b, attrs, key, _c, children, dependencies, chunks, options, comp, lookUpTemplates, compHasSlots, combinedProps, propsForInstance, combinedStates, statesForInstance, elementNode, compTag, cssPlugin, result, chunk, styleChunk; | ||
var _d; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
var generateComponentContent = function (node, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () { | ||
var externals, plugins, _a, elementType, _b, attrs, key, _c, children, dependencies, _d, chunks, options, comp, lookUpTemplates, compHasSlots, combinedProps, propsForInstance, combinedStates, statesForInstance, elementNode, compTag, cssPlugin, initialStructure, result, chunk, styleChunk; | ||
var _e; | ||
return __generator(this, function (_f) { | ||
switch (_f.label) { | ||
case 0: | ||
externals = subComponentOptions.externals, plugins = subComponentOptions.plugins; | ||
_a = node.content, elementType = _a.elementType, _b = _a.attrs, attrs = _b === void 0 ? {} : _b, key = _a.key, _c = _a.children, children = _c === void 0 ? [] : _c; | ||
dependencies = structure.dependencies, chunks = structure.chunks, options = structure.options; | ||
dependencies = structure.dependencies, _d = structure.chunks, chunks = _d === void 0 ? [] : _d, options = structure.options; | ||
comp = UIDLUtils.cloneObject(externals[elementType] || {}); | ||
@@ -219,11 +232,11 @@ lookUpTemplates = {}; | ||
lookUpTemplates[key] = elementNode; | ||
return [4 /*yield*/, generateHtmlSynatx(__assign(__assign({}, comp.node), { content: __assign(__assign({}, comp.node.content), { style: __assign(__assign({}, (((_d = comp.node.content) === null || _d === void 0 ? void 0 : _d.style) || {})), { display: { | ||
return [4 /*yield*/, generateHtmlSynatx(__assign(__assign({}, comp.node), { content: __assign(__assign({}, comp.node.content), { style: __assign(__assign({}, (((_e = comp.node.content) === null || _e === void 0 ? void 0 : _e.style) || {})), { display: { | ||
type: 'static', | ||
content: 'contents', | ||
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, externals, routeDefinitions, structure)]; | ||
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, subComponentOptions, structure)]; | ||
case 1: | ||
compTag = (_e.sent()); | ||
compTag = (_f.sent()); | ||
cssPlugin = createCSSPlugin({ | ||
templateStyle: 'html', | ||
templateChunkName: 'html-template', | ||
templateChunkName: DEFAULT_COMPONENT_CHUNK_NAME, | ||
declareDependency: 'import', | ||
@@ -234,21 +247,32 @@ forceScoping: true, | ||
}); | ||
return [4 /*yield*/, cssPlugin({ | ||
uidl: __assign(__assign({}, comp), { propDefinitions: propsForInstance, stateDefinitions: statesForInstance }), | ||
chunks: [ | ||
{ | ||
type: ChunkType.HAST, | ||
fileType: FileType.HTML, | ||
name: DEFAULT_COMPONENT_CHUNK_NAME, | ||
linkAfter: [], | ||
content: compTag, | ||
meta: { | ||
nodesLookup: lookUpTemplates, | ||
}, | ||
initialStructure = { | ||
uidl: __assign(__assign({}, comp), { propDefinitions: propsForInstance, stateDefinitions: statesForInstance }), | ||
chunks: [ | ||
{ | ||
type: ChunkType.HAST, | ||
fileType: FileType.HTML, | ||
name: DEFAULT_COMPONENT_CHUNK_NAME, | ||
linkAfter: [], | ||
content: compTag, | ||
meta: { | ||
nodesLookup: lookUpTemplates, | ||
}, | ||
], | ||
dependencies: dependencies, | ||
options: options, | ||
})]; | ||
}, | ||
], | ||
dependencies: dependencies, | ||
options: options, | ||
}; | ||
return [4 /*yield*/, __spreadArray([cssPlugin], plugins, true).reduce(function (previousPluginOperation, plugin) { return __awaiter(void 0, void 0, void 0, function () { | ||
var modifiedStructure; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, previousPluginOperation]; | ||
case 1: | ||
modifiedStructure = _a.sent(); | ||
return [2 /*return*/, plugin(modifiedStructure)]; | ||
} | ||
}); | ||
}); }, Promise.resolve(initialStructure))]; | ||
case 2: | ||
result = _e.sent(); | ||
result = _f.sent(); | ||
if (compHasSlots) { | ||
@@ -264,3 +288,6 @@ result.chunks.forEach(function (chunk) { | ||
if (!chunk) { | ||
styleChunk = result.chunks.find(function (item) { return item.name === comp.name; }); | ||
styleChunk = result.chunks.find(function (item) { return item.fileType === FileType.CSS; }); | ||
if (!styleChunk) { | ||
return [2 /*return*/]; | ||
} | ||
chunks.push(styleChunk); | ||
@@ -296,3 +323,3 @@ } | ||
}; | ||
var handleAttributes = function (htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions) { | ||
var handleAttributes = function (elementType, htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions, outputOptions) { | ||
Object.keys(attrs).forEach(function (attrKey) { | ||
@@ -304,9 +331,16 @@ var attrValue = attrs[attrKey]; | ||
attrValue.content.startsWith('/')) { | ||
attrValue = | ||
attrValue.content === '/' || | ||
attrValue.content === | ||
"/".concat(StringUtils.camelCaseToDashCase(StringUtils.removeIllegalCharacters((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.defaultValue) || ''))) | ||
? staticNode('index.html') | ||
: staticNode("".concat(attrValue.content.split('/').pop(), ".html")); | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)); | ||
var targetLink = void 0; | ||
var targetRoute = ((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.values) || []).find(function (route) { return route.pageOptions.navLink === attrValue.content; }); | ||
if (targetRoute) { | ||
targetLink = targetRoute.pageOptions.navLink; | ||
} | ||
if (!targetRoute && attrValue.content === '/home') { | ||
targetLink = '/'; | ||
} | ||
if (!targetLink && !targetRoute) { | ||
targetLink = attrValue.content; | ||
} | ||
var currentPageRoute = join.apply(void 0, __spreadArray(__spreadArray([], ((outputOptions === null || outputOptions === void 0 ? void 0 : outputOptions.folderPath) || []), false), ['./'], false)); | ||
var localPrefix = relative("/".concat(currentPageRoute), "/".concat(targetLink === '/' ? 'index' : targetLink)); | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, "".concat(localPrefix, ".html")); | ||
return; | ||
@@ -322,3 +356,3 @@ } | ||
if (attrValue.type === 'raw') { | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)); | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content); | ||
return; | ||
@@ -331,3 +365,29 @@ } | ||
else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') { | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, StringUtils.encode(String(attrValue.content))); | ||
var value = StringUtils.encode(String(attrValue.content)); | ||
/* | ||
elementType of image is always mapped to img. | ||
For reference, check `html-mapping` file. | ||
*/ | ||
if (elementType === 'img' && attrKey === 'src' && !isValidURL(value)) { | ||
/* | ||
By default we just prefix all the asset paths with just the | ||
assetPrefix that is configured in the project. But for `html` generators | ||
we need to prefix that with the current file location. | ||
Because, all the other frameworks have a build setup. which serves all the | ||
assets from the `public` folder. But in the case of `html` here is how it works | ||
We load a file from `index.html` the request for the image goes from | ||
'...url.../public/...image...' | ||
If it's a nested url, then the request goes from | ||
'...url/nested/public/...image..' | ||
But the nested folder is available only on the root. With this | ||
The url changes prefixes to | ||
../public/playground_assets/..image.. etc depending on the dept the file is in. | ||
*/ | ||
value = join(relative(join.apply(void 0, outputOptions.folderPath), './'), value); | ||
} | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, value); | ||
return; | ||
@@ -338,3 +398,3 @@ } | ||
var getValueFromReference = function (key, definitions) { | ||
var usedReferenceValue = definitions[key]; | ||
var usedReferenceValue = definitions[key.includes('.') ? key.split('.')[0] : key]; | ||
if (!usedReferenceValue) { | ||
@@ -346,3 +406,3 @@ throw new HTMLComponentGeneratorError("Definition for ".concat(key, " is missing from ").concat(JSON.stringify(definitions, null, 2))); | ||
} | ||
if (!['string', 'number'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type)) { | ||
if (!['string', 'number', 'object'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type)) { | ||
throw new HTMLComponentGeneratorError("Attribute is using dynamic value, but received of type ".concat(JSON.stringify(usedReferenceValue, null, 2))); | ||
@@ -349,0 +409,0 @@ } |
{ | ||
"name": "@teleporthq/teleport-plugin-html-base-component", | ||
"version": "0.31.0-alpha.0", | ||
"version": "0.31.0", | ||
"description": "A plugin for handling the skeleton/baseline of a base html component", | ||
@@ -27,9 +27,9 @@ "author": "teleportHQ", | ||
"dependencies": { | ||
"@teleporthq/teleport-plugin-common": "^0.31.0-alpha.0", | ||
"@teleporthq/teleport-plugin-css": "^0.31.0-alpha.0", | ||
"@teleporthq/teleport-shared": "^0.31.0-alpha.0", | ||
"@teleporthq/teleport-types": "^0.31.0-alpha.0", | ||
"@teleporthq/teleport-uidl-builders": "^0.31.0-alpha.0" | ||
"@teleporthq/teleport-plugin-common": "^0.31.0", | ||
"@teleporthq/teleport-plugin-css": "^0.31.0", | ||
"@teleporthq/teleport-shared": "^0.31.0", | ||
"@teleporthq/teleport-types": "^0.31.0", | ||
"@teleporthq/teleport-uidl-builders": "^0.31.0" | ||
}, | ||
"gitHead": "a5289f88f2d0cf8aae4b93bf05777c5492dd86b2" | ||
"gitHead": "37c3970566832845c57f0ef11088a9214af720b2" | ||
} |
@@ -1,1 +0,1 @@ | ||
export const DEFAULT_COMPONENT_CHUNK_NAME = 'html-template' | ||
export const DEFAULT_COMPONENT_CHUNK_NAME = 'html-chunk' |
@@ -21,3 +21,3 @@ import { | ||
htmlComponentPlugin: ComponentPlugin | ||
addExternals: (list: Record<string, ComponentUIDL>) => void | ||
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void | ||
} | ||
@@ -30,4 +30,8 @@ | ||
let externals: Record<string, ComponentUIDL> = {} | ||
let plugins: ComponentPlugin[] = [] | ||
const addExternals = (list?: Record<string, ComponentUIDL>) => { | ||
const addExternals = ( | ||
list?: Record<string, ComponentUIDL>, | ||
subComponentPlugins: ComponentPlugin[] = [] | ||
) => { | ||
externals = { | ||
@@ -37,7 +41,8 @@ ...externals, | ||
} | ||
plugins = subComponentPlugins | ||
} | ||
const htmlComponentPlugin: ComponentPlugin = async (structure) => { | ||
const { uidl, chunks, dependencies, options } = structure | ||
const { propDefinitions = {}, stateDefinitions = {} } = uidl | ||
const { uidl, chunks = [], dependencies, options } = structure | ||
const { propDefinitions = {}, stateDefinitions = {}, outputOptions } = uidl | ||
@@ -54,11 +59,16 @@ const templatesLookUp: Record<string, unknown> = {} | ||
stateDefinitions, | ||
Object.values(externals).reduce((acc: Record<string, ComponentUIDL>, comp: ComponentUIDL) => { | ||
UIDLUtils.setFriendlyOutputOptions(comp) | ||
comp.name = StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent' | ||
comp.name = UIDLUtils.getComponentClassName(comp) | ||
acc[comp.name] = comp | ||
return acc | ||
}, {}), | ||
options.projectRouteDefinition, | ||
{ chunks, dependencies, options } | ||
{ | ||
externals: Object.values(externals).reduce( | ||
(acc: Record<string, ComponentUIDL>, comp: ComponentUIDL) => { | ||
UIDLUtils.setFriendlyOutputOptions(comp) | ||
comp.name = StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent' | ||
comp.name = UIDLUtils.getComponentClassName(comp) | ||
acc[comp.name] = comp | ||
return acc | ||
}, | ||
{} | ||
), | ||
plugins, | ||
}, | ||
{ chunks, dependencies, options, outputOptions } | ||
) | ||
@@ -65,0 +75,0 @@ HASTUtils.addChildNode(compBase, bodyContent as HastNode) |
@@ -20,3 +20,8 @@ import { | ||
UIDLRouteDefinitions, | ||
ComponentPlugin, | ||
ComponentStructure, | ||
UIDLComponentOutputOptions, | ||
UIDLElement, | ||
} from '@teleporthq/teleport-types' | ||
import { join, relative } from 'path' | ||
import { HASTBuilders, HASTUtils } from '@teleporthq/teleport-plugin-common' | ||
@@ -28,2 +33,12 @@ import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared' | ||
const isValidURL = (url: string) => { | ||
try { | ||
/* tslint:disable:no-unused-expression */ | ||
new URL(url) | ||
return true | ||
} catch (error) { | ||
return false | ||
} | ||
} | ||
type NodeToHTML<NodeType, ReturnType> = ( | ||
@@ -34,4 +49,6 @@ node: NodeType, | ||
stateDefinitions: Record<string, UIDLStateDefinition>, | ||
externals: Record<string, ComponentUIDL>, | ||
routeDefinitions: UIDLRouteDefinitions, | ||
subComponentOptions: { | ||
externals: Record<string, ComponentUIDL> | ||
plugins: ComponentPlugin[] | ||
}, | ||
structure: { | ||
@@ -41,2 +58,3 @@ chunks: ChunkDefinition[] | ||
options: GeneratorOptions | ||
outputOptions: UIDLComponentOutputOptions | ||
} | ||
@@ -50,7 +68,7 @@ ) => ReturnType | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
) => { | ||
switch (node.type) { | ||
case 'inject': | ||
case 'raw': | ||
@@ -71,4 +89,3 @@ return HASTBuilders.createTextNode(node.content.toString()) | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -83,4 +100,3 @@ ) | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -105,4 +121,3 @@ ) | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -119,3 +134,2 @@ ) => { | ||
} = node.content | ||
const elementNode = HASTBuilders.createHTMLNode(elementType) | ||
@@ -134,4 +148,3 @@ templatesLookUp[key] = elementNode | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -149,4 +162,3 @@ ) | ||
stateDefinitions, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -182,3 +194,11 @@ ) | ||
if (Object.keys(attrs).length > 0) { | ||
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions) | ||
handleAttributes( | ||
elementType, | ||
elementNode, | ||
attrs, | ||
propDefinitions, | ||
stateDefinitions, | ||
structure.options.projectRouteDefinition, | ||
structure.outputOptions | ||
) | ||
} | ||
@@ -193,4 +213,6 @@ | ||
stateDefinitions: Record<string, UIDLStateDefinition>, | ||
externals: Record<string, ComponentUIDL>, | ||
routeDefinitions: UIDLRouteDefinitions, | ||
subComponentOptions: { | ||
externals: Record<string, ComponentUIDL> | ||
plugins: ComponentPlugin[] | ||
}, | ||
structure: { | ||
@@ -200,6 +222,8 @@ chunks: ChunkDefinition[] | ||
options: GeneratorOptions | ||
outputOptions: UIDLComponentOutputOptions | ||
} | ||
) => { | ||
const { externals, plugins } = subComponentOptions | ||
const { elementType, attrs = {}, key, children = [] } = node.content | ||
const { dependencies, chunks, options } = structure | ||
const { dependencies, chunks = [], options } = structure | ||
const comp = UIDLUtils.cloneObject(externals[elementType] || {}) as ComponentUIDL | ||
@@ -246,3 +270,2 @@ const lookUpTemplates: Record<string, unknown> = {} | ||
const combinedProps = { ...propDefinitions, ...(comp?.propDefinitions || {}) } | ||
const propsForInstance = Object.keys(combinedProps).reduce( | ||
@@ -280,3 +303,2 @@ (acc: Record<string, UIDLPropDefinition>, propKey) => { | ||
) | ||
const elementNode = HASTBuilders.createHTMLNode(StringUtils.camelCaseToDashCase(elementType)) | ||
@@ -302,4 +324,3 @@ lookUpTemplates[key] = elementNode | ||
statesForInstance, | ||
externals, | ||
routeDefinitions, | ||
subComponentOptions, | ||
structure | ||
@@ -310,3 +331,3 @@ )) as unknown as HastNode | ||
templateStyle: 'html', | ||
templateChunkName: 'html-template', | ||
templateChunkName: DEFAULT_COMPONENT_CHUNK_NAME, | ||
declareDependency: 'import', | ||
@@ -318,3 +339,3 @@ forceScoping: true, | ||
const result = await cssPlugin({ | ||
const initialStructure: ComponentStructure = { | ||
uidl: { | ||
@@ -339,4 +360,12 @@ ...comp, | ||
options, | ||
}) | ||
} | ||
const result = await [cssPlugin, ...plugins].reduce( | ||
async (previousPluginOperation: Promise<ComponentStructure>, plugin) => { | ||
const modifiedStructure = await previousPluginOperation | ||
return plugin(modifiedStructure) | ||
}, | ||
Promise.resolve(initialStructure) | ||
) | ||
if (compHasSlots) { | ||
@@ -351,3 +380,8 @@ result.chunks.forEach((chunk) => { | ||
if (!chunk) { | ||
const styleChunk = result.chunks.find((item: ChunkDefinition) => item.name === comp.name) | ||
const styleChunk = result.chunks.find( | ||
(item: ChunkDefinition) => item.fileType === FileType.CSS | ||
) | ||
if (!styleChunk) { | ||
return | ||
} | ||
chunks.push(styleChunk) | ||
@@ -396,2 +430,3 @@ } | ||
const handleAttributes = ( | ||
elementType: UIDLElement['elementType'], | ||
htmlNode: HastNode, | ||
@@ -401,6 +436,7 @@ attrs: Record<string, UIDLAttributeValue>, | ||
stateDefinitions: Record<string, UIDLStateDefinition>, | ||
routeDefinitions: UIDLRouteDefinitions | ||
routeDefinitions: UIDLRouteDefinitions, | ||
outputOptions: UIDLComponentOutputOptions | ||
) => { | ||
Object.keys(attrs).forEach((attrKey) => { | ||
let attrValue = attrs[attrKey] | ||
const attrValue = attrs[attrKey] | ||
@@ -413,11 +449,27 @@ if ( | ||
) { | ||
attrValue = | ||
attrValue.content === '/' || | ||
attrValue.content === | ||
`/${StringUtils.camelCaseToDashCase( | ||
StringUtils.removeIllegalCharacters(routeDefinitions?.defaultValue || '') | ||
)}` | ||
? staticNode('index.html') | ||
: staticNode(`${attrValue.content.split('/').pop()}.html`) | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)) | ||
let targetLink | ||
const targetRoute = (routeDefinitions?.values || []).find( | ||
(route) => route.pageOptions.navLink === attrValue.content | ||
) | ||
if (targetRoute) { | ||
targetLink = targetRoute.pageOptions.navLink | ||
} | ||
if (!targetRoute && attrValue.content === '/home') { | ||
targetLink = '/' | ||
} | ||
if (!targetLink && !targetRoute) { | ||
targetLink = attrValue.content | ||
} | ||
const currentPageRoute = join(...(outputOptions?.folderPath || []), './') | ||
const localPrefix = relative( | ||
`/${currentPageRoute}`, | ||
`/${targetLink === '/' ? 'index' : targetLink}` | ||
) | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, `${localPrefix}.html`) | ||
return | ||
@@ -436,3 +488,3 @@ } | ||
if (attrValue.type === 'raw') { | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(attrValue.content)) | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content) | ||
return | ||
@@ -445,3 +497,31 @@ } | ||
} else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') { | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, StringUtils.encode(String(attrValue.content))) | ||
let value = StringUtils.encode(String(attrValue.content)) | ||
/* | ||
elementType of image is always mapped to img. | ||
For reference, check `html-mapping` file. | ||
*/ | ||
if (elementType === 'img' && attrKey === 'src' && !isValidURL(value)) { | ||
/* | ||
By default we just prefix all the asset paths with just the | ||
assetPrefix that is configured in the project. But for `html` generators | ||
we need to prefix that with the current file location. | ||
Because, all the other frameworks have a build setup. which serves all the | ||
assets from the `public` folder. But in the case of `html` here is how it works | ||
We load a file from `index.html` the request for the image goes from | ||
'...url.../public/...image...' | ||
If it's a nested url, then the request goes from | ||
'...url/nested/public/...image..' | ||
But the nested folder is available only on the root. With this | ||
The url changes prefixes to | ||
../public/playground_assets/..image.. etc depending on the dept the file is in. | ||
*/ | ||
value = join(relative(join(...outputOptions.folderPath), './'), value) | ||
} | ||
HASTUtils.addAttributeToNode(htmlNode, attrKey, value) | ||
return | ||
@@ -456,3 +536,3 @@ } | ||
): string => { | ||
const usedReferenceValue = definitions[key] | ||
const usedReferenceValue = definitions[key.includes('.') ? key.split('.')[0] : key] | ||
@@ -475,3 +555,3 @@ if (!usedReferenceValue) { | ||
if (!['string', 'number'].includes(usedReferenceValue?.type)) { | ||
if (!['string', 'number', 'object'].includes(usedReferenceValue?.type)) { | ||
throw new HTMLComponentGeneratorError( | ||
@@ -478,0 +558,0 @@ `Attribute is using dynamic value, but received of type ${JSON.stringify( |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
164847
1702