New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@teleporthq/teleport-plugin-html-base-component

Package Overview
Dependencies
Maintainers
0
Versions
106
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@teleporthq/teleport-plugin-html-base-component - npm Package Compare versions

Comparing version 0.34.0-alpha.0 to 0.34.0

46

__tests__/index.ts

@@ -11,13 +11,15 @@ import {

const getMockComponentStructure = (): ComponentStructure => ({
chunks: [],
options: {
extractedResources: {},
},
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 +29,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 +45,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 +53,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 +75,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 +85,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 +91,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,3 +8,3 @@ import { ComponentPlugin, ComponentDefaultPluginParams, ComponentUIDL } from '@teleporthq/teleport-types';

htmlComponentPlugin: ComponentPlugin;
addExternals: (list: Record<string, ComponentUIDL>) => void;
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void;
}

@@ -11,0 +11,0 @@ type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin;

@@ -59,17 +59,21 @@ "use strict";

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, nodesLookup, compBase, subComponents, templateOptions, _i, _d, propKey, prop, bodyContent;
return __generator(this, function (_e) {
switch (_e.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;
templatesLookUp = {};
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;
nodesLookup = {};
compBase = wrapComponent
? teleport_plugin_common_1.HASTBuilders.createHTMLNode('body')
: 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) {
subComponents = {
externals: Object.values(externals).reduce(function (acc, comp) {
teleport_shared_1.UIDLUtils.setFriendlyOutputOptions(comp);

@@ -80,5 +84,25 @@ comp.name = teleport_shared_1.StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent';

return acc;
}, {}), options.projectRouteDefinition, { chunks: chunks, dependencies: dependencies, options: options })];
}, {}),
plugins: plugins,
};
templateOptions = { chunks: chunks, dependencies: dependencies, options: options, outputOptions: outputOptions };
_i = 0, _d = Object.keys(propDefinitions);
_e.label = 1;
case 1:
bodyContent = _c.sent();
if (!(_i < _d.length)) return [3 /*break*/, 4];
propKey = _d[_i];
prop = propDefinitions[propKey];
if (!(prop.type === 'element' &&
prop.defaultValue !== undefined &&
typeof prop.defaultValue === 'object')) return [3 /*break*/, 3];
return [4 /*yield*/, (0, node_handlers_1.generateHtmlSyntax)(prop.defaultValue, nodesLookup, propDefinitions, stateDefinitions, subComponents, templateOptions)];
case 2:
_e.sent();
_e.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4: return [4 /*yield*/, (0, node_handlers_1.generateHtmlSyntax)(uidl.node, nodesLookup, propDefinitions, stateDefinitions, subComponents, templateOptions)];
case 5:
bodyContent = _e.sent();
teleport_plugin_common_1.HASTUtils.addChildNode(compBase, bodyContent);

@@ -92,3 +116,3 @@ chunks.push({

meta: {
nodesLookup: templatesLookUp,
nodesLookup: nodesLookup,
},

@@ -95,0 +119,0 @@ });

@@ -1,9 +0,13 @@

import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, UIDLRouteDefinitions } from '@teleporthq/teleport-types';
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, nodesLookup: Record<string, HastNode | HastText>, 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;
export declare const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>;
export declare const generateHtmlSyntax: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>;
export {};
//# sourceMappingURL=node-handlers.d.ts.map

@@ -59,4 +59,5 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.generateHtmlSynatx = void 0;
exports.generateHtmlSyntax = void 0;
var teleport_types_1 = require("@teleporthq/teleport-types");
var path_1 = require("path");
var teleport_plugin_common_1 = require("@teleporthq/teleport-plugin-common");

@@ -67,31 +68,49 @@ 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 () {
return __generator(this, function (_a) {
switch (node.type) {
case 'inject':
case 'raw':
return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createTextNode(node.content.toString())];
case 'static':
return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createTextNode(teleport_shared_1.StringUtils.encode(node.content.toString()))];
case 'slot':
return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createHTMLNode(node.type)];
case 'element':
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
case 'dynamic':
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
default:
throw new teleport_types_1.HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " "));
var isValidURL = function (url) {
try {
/* tslint:disable:no-unused-expression */
new URL(url);
return true;
}
catch (error) {
return false;
}
};
var generateHtmlSyntax = function (node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () {
var _a, elementNode, dynamicNode;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = node.type;
switch (_a) {
case 'inject': return [3 /*break*/, 1];
case 'raw': return [3 /*break*/, 1];
case 'static': return [3 /*break*/, 2];
case 'slot': return [3 /*break*/, 3];
case 'element': return [3 /*break*/, 4];
case 'dynamic': return [3 /*break*/, 6];
}
return [3 /*break*/, 8];
case 1: return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createTextNode(node.content.toString())];
case 2: return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createTextNode(teleport_shared_1.StringUtils.encode(node.content.toString()))];
case 3: return [2 /*return*/, teleport_plugin_common_1.HASTBuilders.createHTMLNode(node.type)];
case 4: return [4 /*yield*/, generateElementNode(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 5:
elementNode = _b.sent();
return [2 /*return*/, elementNode];
case 6: return [4 /*yield*/, generateDynamicNode(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 7:
dynamicNode = _b.sent();
return [2 /*return*/, dynamicNode];
case 8: throw new teleport_types_1.HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " "));
}
return [2 /*return*/];
});
}); };
exports.generateHtmlSynatx = generateHtmlSynatx;
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, 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;
return __generator(this, function (_e) {
switch (_e.label) {
exports.generateHtmlSyntax = generateHtmlSyntax;
var generateElementNode = function (node, nodesLookup, 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, dependencies, _i, _e, attrKey, attr, compTag, elementNode, _f, children_1, child, childTag;
return __generator(this, function (_g) {
switch (_g.label) {
case 0:
_a = node.content, elementType = _a.elementType, children = _a.children, _b = _a.attrs, attrs = _b === void 0 ? {} : _b, _c = _a.style, style = _c === void 0 ? {} : _c, _d = _a.referencedStyles, referencedStyles = _d === void 0 ? {} : _d, dependency = _a.dependency, key = _a.key;
elementNode = teleport_plugin_common_1.HASTBuilders.createHTMLNode(elementType);
templatesLookUp[key] = elementNode;
dependencies = structure.dependencies;

@@ -101,20 +120,32 @@ if (dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) !== 'local') {

}
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)];
if (!(dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) === 'local')) return [3 /*break*/, 6];
_i = 0, _e = Object.keys(attrs);
_g.label = 1;
case 1:
compTag = _e.sent();
return [2 /*return*/, compTag];
if (!(_i < _e.length)) return [3 /*break*/, 4];
attrKey = _e[_i];
attr = attrs[attrKey];
if (!(attr.type === 'element')) return [3 /*break*/, 3];
return [4 /*yield*/, generateElementNode(attr, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 2:
if (!children) return [3 /*break*/, 6];
_i = 0, children_1 = children;
_e.label = 3;
_g.sent();
_g.label = 3;
case 3:
if (!(_i < children_1.length)) return [3 /*break*/, 6];
child = children_1[_i];
return [4 /*yield*/, (0, exports.generateHtmlSynatx)(child, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
case 4:
childTag = _e.sent();
if (!childTag) {
return [2 /*return*/];
}
_i++;
return [3 /*break*/, 1];
case 4: return [4 /*yield*/, generateComponentContent(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 5:
compTag = _g.sent();
return [2 /*return*/, compTag];
case 6:
elementNode = teleport_plugin_common_1.HASTBuilders.createHTMLNode(elementType);
if (!children) return [3 /*break*/, 10];
_f = 0, children_1 = children;
_g.label = 7;
case 7:
if (!(_f < children_1.length)) return [3 /*break*/, 10];
child = children_1[_f];
return [4 /*yield*/, (0, exports.generateHtmlSyntax)(child, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 8:
childTag = _g.sent();
if (typeof childTag === 'string') {

@@ -126,7 +157,7 @@ teleport_plugin_common_1.HASTUtils.addTextNode(elementNode, childTag);

}
_e.label = 5;
case 5:
_i++;
return [3 /*break*/, 3];
case 6:
_g.label = 9;
case 9:
_f++;
return [3 /*break*/, 7];
case 10:
if (Object.keys(referencedStyles).length > 0) {

@@ -144,5 +175,4 @@ Object.keys(referencedStyles).forEach(function (styleRef) {

}
if (Object.keys(attrs).length > 0) {
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions);
}
handleAttributes(elementType, elementNode, attrs, propDefinitions, stateDefinitions, structure.options.projectRouteDefinition, structure.outputOptions);
nodesLookup[key] = elementNode;
return [2 /*return*/, elementNode];

@@ -152,19 +182,21 @@ }

}); };
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, nodesLookup, 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, compName, component, componentClone, compHasSlots, combinedProps, propsForInstance, _i, _e, propKey, combinedStates, statesForInstance, componentWrapper, isExistingNode, componentInstanceToGenerate, compTag, cssPlugin, initialStructure, result, chunk, styleChunk;
var _f, _g, _h;
return __generator(this, function (_j) {
switch (_j.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;
comp = teleport_shared_1.UIDLUtils.cloneObject(externals[elementType] || {});
lookUpTemplates = {};
dependencies = structure.dependencies, _d = structure.chunks, chunks = _d === void 0 ? [] : _d, options = structure.options;
compName = elementType === 'Component' ? 'AppComponent' : elementType;
component = externals[compName];
if (component === undefined) {
throw new teleport_types_1.HTMLComponentGeneratorError("".concat(compName, " is missing from externals object"));
}
componentClone = teleport_shared_1.UIDLUtils.cloneObject(component);
compHasSlots = false;
if (!comp || !(comp === null || comp === void 0 ? void 0 : comp.node)) {
throw new teleport_types_1.HTMLComponentGeneratorError("".concat(elementType, " is not found from the externals. \n\n Received ").concat(JSON.stringify(Object.keys(externals), null, 2)));
}
if (children.length) {
compHasSlots = true;
teleport_shared_1.UIDLUtils.traverseNodes(comp.node, function (childNode, parentNode) {
teleport_shared_1.UIDLUtils.traverseNodes(componentClone.node, function (childNode, parentNode) {
var _a, _b;

@@ -197,14 +229,18 @@ if (childNode.type === 'slot' && parentNode.type === 'element') {

}
combinedProps = __assign(__assign({}, propDefinitions), ((comp === null || comp === void 0 ? void 0 : comp.propDefinitions) || {}));
propsForInstance = Object.keys(combinedProps).reduce(function (acc, propKey) {
var _a, _b;
if (attrs[propKey]) {
acc[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: ((_a = attrs[propKey]) === null || _a === void 0 ? void 0 : _a.content) || ((_b = combinedProps[propKey]) === null || _b === void 0 ? void 0 : _b.defaultValue) });
combinedProps = __assign(__assign({}, propDefinitions), ((componentClone === null || componentClone === void 0 ? void 0 : componentClone.propDefinitions) || {}));
propsForInstance = {};
for (_i = 0, _e = Object.keys(combinedProps); _i < _e.length; _i++) {
propKey = _e[_i];
// If the attribute is a named-slot, then we can directly pass the value instead of just the content
if (((_f = attrs[propKey]) === null || _f === void 0 ? void 0 : _f.type) === 'element') {
propsForInstance[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: attrs[propKey] });
}
else if (attrs[propKey]) {
propsForInstance[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: ((_g = attrs[propKey]) === null || _g === void 0 ? void 0 : _g.content) || ((_h = combinedProps[propKey]) === null || _h === void 0 ? void 0 : _h.defaultValue) });
}
else {
acc[propKey] = combinedProps[propKey];
propsForInstance[propKey] = combinedProps[propKey];
}
return acc;
}, {});
combinedStates = __assign(__assign({}, stateDefinitions), ((comp === null || comp === void 0 ? void 0 : comp.stateDefinitions) || {}));
}
combinedStates = __assign(__assign({}, stateDefinitions), ((componentClone === null || componentClone === void 0 ? void 0 : componentClone.stateDefinitions) || {}));
statesForInstance = Object.keys(combinedStates).reduce(function (acc, propKey) {

@@ -220,37 +256,62 @@ var _a, _b;

}, {});
elementNode = teleport_plugin_common_1.HASTBuilders.createHTMLNode(teleport_shared_1.StringUtils.camelCaseToDashCase(elementType));
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: {
type: 'static',
content: 'contents',
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, externals, routeDefinitions, structure)];
componentWrapper = teleport_shared_1.StringUtils.camelCaseToDashCase("".concat(compName, "-wrapper"));
isExistingNode = nodesLookup[componentWrapper];
if (isExistingNode !== undefined) {
componentWrapper = "".concat(componentWrapper, "-").concat(teleport_shared_1.StringUtils.generateRandomString());
}
componentInstanceToGenerate = {
type: 'element',
content: {
elementType: componentWrapper,
key: componentWrapper,
children: [componentClone.node],
style: {
display: {
type: 'static',
content: 'contents',
},
},
},
};
return [4 /*yield*/, (0, exports.generateHtmlSyntax)(componentInstanceToGenerate, nodesLookup, propsForInstance, statesForInstance, subComponentOptions, structure)];
case 1:
compTag = (_e.sent());
compTag = _j.sent();
cssPlugin = (0, teleport_plugin_css_1.createCSSPlugin)({
templateStyle: 'html',
templateChunkName: 'html-template',
templateChunkName: constants_1.DEFAULT_COMPONENT_CHUNK_NAME,
declareDependency: 'import',
forceScoping: true,
chunkName: comp.name,
chunkName: componentClone.name,
staticPropReferences: 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({}, componentClone), { 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: nodesLookup,
},
],
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 = _j.sent();
if (compHasSlots) {

@@ -264,8 +325,12 @@ result.chunks.forEach(function (chunk) {

else {
chunk = chunks.find(function (item) { return item.name === comp.name; });
chunk = chunks.find(function (item) { return item.name === componentClone.name; });
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);
}
}
nodesLookup[key] = compTag;
return [2 /*return*/, compTag];

@@ -275,10 +340,26 @@ }

}); };
var generateDynamicNode = function (node, _, propDefinitions, stateDefinitions) {
var spanTag = teleport_plugin_common_1.HASTBuilders.createHTMLNode('span');
var usedReferenceValue = node.content.referenceType === 'prop'
? getValueFromReference(node.content.id, propDefinitions)
: getValueFromReference(node.content.id, stateDefinitions);
teleport_plugin_common_1.HASTUtils.addTextNode(spanTag, String(usedReferenceValue));
return spanTag;
};
var generateDynamicNode = function (node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () {
var usedReferenceValue, slotNode, spanTagWrapper, commentNode, spanTag;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
usedReferenceValue = getValueFromReference(node.content.id, node.content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
if (!(usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue)) return [3 /*break*/, 2];
return [4 /*yield*/, generateElementNode(usedReferenceValue.defaultValue, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 1:
slotNode = _a.sent();
return [2 /*return*/, slotNode];
case 2:
if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue === undefined) {
spanTagWrapper = teleport_plugin_common_1.HASTBuilders.createHTMLNode('span');
commentNode = teleport_plugin_common_1.HASTBuilders.createComment("Content for slot ".concat(node.content.id));
teleport_plugin_common_1.HASTUtils.addChildNode(spanTagWrapper, commentNode);
return [2 /*return*/, spanTagWrapper];
}
spanTag = teleport_plugin_common_1.HASTBuilders.createHTMLNode('span');
teleport_plugin_common_1.HASTUtils.addTextNode(spanTag, String(usedReferenceValue.defaultValue));
return [2 /*return*/, spanTag];
}
});
}); };
var handleStyles = function (node, styles, propDefinitions, stateDefinitions) {

@@ -289,8 +370,6 @@ Object.keys(styles).forEach(function (styleKey) {

if (style.type === 'dynamic' && ((_a = style.content) === null || _a === void 0 ? void 0 : _a.referenceType) !== 'token') {
if (style.content.referenceType === 'prop') {
style = getValueFromReference(style.content.id, propDefinitions);
var referencedValue = getValueFromReference(style.content.id, style.content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
if (referencedValue.type === 'string' || referencedValue.type === 'number') {
style = String(referencedValue.defaultValue);
}
else if (style.content.referenceType === 'state') {
style = getValueFromReference(style.content.id, stateDefinitions);
}
node.content.style[styleKey] = typeof style === 'string' ? (0, teleport_uidl_builders_1.staticNode)(style) : style;

@@ -300,38 +379,81 @@ }

};
var handleAttributes = function (htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions) {
Object.keys(attrs).forEach(function (attrKey) {
var handleAttributes = function (elementType, htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions, outputOptions) {
var _loop_1 = function (attrKey) {
var attrValue = attrs[attrKey];
if (attrKey === 'href' &&
attrValue.type === 'static' &&
typeof attrValue.content === 'string' &&
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));
return;
var type = attrValue.type, content = attrValue.content;
switch (type) {
case 'static': {
if (attrKey === 'href' && typeof content === 'string' && content.startsWith('/')) {
var targetLink = void 0;
var targetRoute = ((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.values) || []).find(function (route) { return route.pageOptions.navLink === content; });
if (targetRoute) {
targetLink = targetRoute.pageOptions.navLink;
}
if (!targetRoute && content === '/home') {
targetLink = '/';
}
if (!targetLink && !targetRoute) {
targetLink = 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"));
break;
}
if (typeof content === 'boolean') {
htmlNode.properties[attrKey] = content === true ? 'true' : 'false';
}
else if (typeof content === 'string' || typeof attrValue.content === 'number') {
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);
}
break;
}
case 'dynamic': {
var value = getValueFromReference(content.id, content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value.defaultValue));
break;
}
case 'raw': {
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, content);
break;
}
case 'element':
case 'import':
case 'expr':
break;
default: {
throw new teleport_types_1.HTMLComponentGeneratorError("Received ".concat(JSON.stringify(attrValue, null, 2), " \n in handleAttributes for html"));
}
}
if (attrValue.type === 'dynamic') {
var value = attrValue.content.referenceType === 'prop'
? getValueFromReference(attrValue.content.id, propDefinitions)
: getValueFromReference(attrValue.content.id, stateDefinitions);
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value));
return;
}
if (attrValue.type === 'raw') {
teleport_plugin_common_1.HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content);
return;
}
if (typeof attrValue.content === 'boolean') {
teleport_plugin_common_1.HASTUtils.addBooleanAttributeToNode(htmlNode, attrKey);
return;
}
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)));
return;
}
});
};
for (var _i = 0, _a = Object.keys(attrs); _i < _a.length; _i++) {
var attrKey = _a[_i];
_loop_1(attrKey);
}
};

@@ -343,10 +465,11 @@ var getValueFromReference = function (key, definitions) {

}
if (!usedReferenceValue.hasOwnProperty('defaultValue')) {
if (['string', 'number', 'object', 'element'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type) === false) {
throw new teleport_types_1.HTMLComponentGeneratorError("Attribute is using dynamic value, but received of type ".concat(JSON.stringify(usedReferenceValue, null, 2)));
}
if (usedReferenceValue.type !== 'element' &&
usedReferenceValue.hasOwnProperty('defaultValue') === false) {
throw new teleport_types_1.HTMLComponentGeneratorError("Default value is missing from dynamic reference - ".concat(JSON.stringify(usedReferenceValue, null, 2)));
}
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)));
}
return String(usedReferenceValue.defaultValue);
return usedReferenceValue;
};
//# sourceMappingURL=node-handlers.js.map

@@ -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,3 +8,3 @@ import { ComponentPlugin, ComponentDefaultPluginParams, ComponentUIDL } from '@teleporthq/teleport-types';

htmlComponentPlugin: ComponentPlugin;
addExternals: (list: Record<string, ComponentUIDL>) => void;
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void;
}

@@ -11,0 +11,0 @@ type HtmlPluginFactory<T> = (config?: Partial<T & ComponentDefaultPluginParams>) => HtmlPlugin;

@@ -51,3 +51,3 @@ var __assign = (this && this.__assign) || function () {

import { DEFAULT_COMPONENT_CHUNK_NAME } from './constants';
import { generateHtmlSynatx } from './node-handlers';
import { generateHtmlSyntax } from './node-handlers';
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared';

@@ -57,17 +57,21 @@ export var createHTMLBasePlugin = function (config) {

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, nodesLookup, compBase, subComponents, templateOptions, _i, _d, propKey, prop, bodyContent;
return __generator(this, function (_e) {
switch (_e.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;
templatesLookUp = {};
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;
nodesLookup = {};
compBase = wrapComponent
? HASTBuilders.createHTMLNode('body')
: HASTBuilders.createHTMLNode('div');
return [4 /*yield*/, generateHtmlSynatx(uidl.node, templatesLookUp, propDefinitions, stateDefinitions, Object.values(externals).reduce(function (acc, comp) {
subComponents = {
externals: Object.values(externals).reduce(function (acc, comp) {
UIDLUtils.setFriendlyOutputOptions(comp);

@@ -78,5 +82,25 @@ comp.name = StringUtils.removeIllegalCharacters(comp.name) || 'AppComponent';

return acc;
}, {}), options.projectRouteDefinition, { chunks: chunks, dependencies: dependencies, options: options })];
}, {}),
plugins: plugins,
};
templateOptions = { chunks: chunks, dependencies: dependencies, options: options, outputOptions: outputOptions };
_i = 0, _d = Object.keys(propDefinitions);
_e.label = 1;
case 1:
bodyContent = _c.sent();
if (!(_i < _d.length)) return [3 /*break*/, 4];
propKey = _d[_i];
prop = propDefinitions[propKey];
if (!(prop.type === 'element' &&
prop.defaultValue !== undefined &&
typeof prop.defaultValue === 'object')) return [3 /*break*/, 3];
return [4 /*yield*/, generateHtmlSyntax(prop.defaultValue, nodesLookup, propDefinitions, stateDefinitions, subComponents, templateOptions)];
case 2:
_e.sent();
_e.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4: return [4 /*yield*/, generateHtmlSyntax(uidl.node, nodesLookup, propDefinitions, stateDefinitions, subComponents, templateOptions)];
case 5:
bodyContent = _e.sent();
HASTUtils.addChildNode(compBase, bodyContent);

@@ -90,3 +114,3 @@ chunks.push({

meta: {
nodesLookup: templatesLookUp,
nodesLookup: nodesLookup,
},

@@ -93,0 +117,0 @@ });

@@ -1,9 +0,13 @@

import { UIDLNode, HastNode, UIDLPropDefinition, UIDLStateDefinition, HastText, ComponentUIDL, ChunkDefinition, UIDLDependency, GeneratorOptions, UIDLRouteDefinitions } from '@teleporthq/teleport-types';
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, nodesLookup: Record<string, HastNode | HastText>, 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;
export declare const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>;
export declare const generateHtmlSyntax: NodeToHTML<UIDLNode, Promise<HastNode | HastText>>;
export {};
//# sourceMappingURL=node-handlers.d.ts.map

@@ -58,2 +58,3 @@ var __assign = (this && this.__assign) || function () {

import { HTMLComponentGeneratorError, ChunkType, FileType, } from '@teleporthq/teleport-types';
import { join, relative } from 'path';
import { HASTBuilders, HASTUtils } from '@teleporthq/teleport-plugin-common';

@@ -64,30 +65,48 @@ 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 () {
return __generator(this, function (_a) {
switch (node.type) {
case 'inject':
case 'raw':
return [2 /*return*/, HASTBuilders.createTextNode(node.content.toString())];
case 'static':
return [2 /*return*/, HASTBuilders.createTextNode(StringUtils.encode(node.content.toString()))];
case 'slot':
return [2 /*return*/, HASTBuilders.createHTMLNode(node.type)];
case 'element':
return [2 /*return*/, generatElementNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
case 'dynamic':
return [2 /*return*/, generateDynamicNode(node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
default:
throw new HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " "));
var isValidURL = function (url) {
try {
/* tslint:disable:no-unused-expression */
new URL(url);
return true;
}
catch (error) {
return false;
}
};
export var generateHtmlSyntax = function (node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () {
var _a, elementNode, dynamicNode;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = node.type;
switch (_a) {
case 'inject': return [3 /*break*/, 1];
case 'raw': return [3 /*break*/, 1];
case 'static': return [3 /*break*/, 2];
case 'slot': return [3 /*break*/, 3];
case 'element': return [3 /*break*/, 4];
case 'dynamic': return [3 /*break*/, 6];
}
return [3 /*break*/, 8];
case 1: return [2 /*return*/, HASTBuilders.createTextNode(node.content.toString())];
case 2: return [2 /*return*/, HASTBuilders.createTextNode(StringUtils.encode(node.content.toString()))];
case 3: return [2 /*return*/, HASTBuilders.createHTMLNode(node.type)];
case 4: return [4 /*yield*/, generateElementNode(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 5:
elementNode = _b.sent();
return [2 /*return*/, elementNode];
case 6: return [4 /*yield*/, generateDynamicNode(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 7:
dynamicNode = _b.sent();
return [2 /*return*/, dynamicNode];
case 8: throw new HTMLComponentGeneratorError("generateHtmlSyntax encountered a node of unsupported type: ".concat(JSON.stringify(node, null, 2), " "));
}
return [2 /*return*/];
});
}); };
var generatElementNode = function (node, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, 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;
return __generator(this, function (_e) {
switch (_e.label) {
var generateElementNode = function (node, nodesLookup, 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, dependencies, _i, _e, attrKey, attr, compTag, elementNode, _f, children_1, child, childTag;
return __generator(this, function (_g) {
switch (_g.label) {
case 0:
_a = node.content, elementType = _a.elementType, children = _a.children, _b = _a.attrs, attrs = _b === void 0 ? {} : _b, _c = _a.style, style = _c === void 0 ? {} : _c, _d = _a.referencedStyles, referencedStyles = _d === void 0 ? {} : _d, dependency = _a.dependency, key = _a.key;
elementNode = HASTBuilders.createHTMLNode(elementType);
templatesLookUp[key] = elementNode;
dependencies = structure.dependencies;

@@ -97,20 +116,32 @@ if (dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) !== 'local') {

}
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)];
if (!(dependency && (dependency === null || dependency === void 0 ? void 0 : dependency.type) === 'local')) return [3 /*break*/, 6];
_i = 0, _e = Object.keys(attrs);
_g.label = 1;
case 1:
compTag = _e.sent();
return [2 /*return*/, compTag];
if (!(_i < _e.length)) return [3 /*break*/, 4];
attrKey = _e[_i];
attr = attrs[attrKey];
if (!(attr.type === 'element')) return [3 /*break*/, 3];
return [4 /*yield*/, generateElementNode(attr, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 2:
if (!children) return [3 /*break*/, 6];
_i = 0, children_1 = children;
_e.label = 3;
_g.sent();
_g.label = 3;
case 3:
if (!(_i < children_1.length)) return [3 /*break*/, 6];
child = children_1[_i];
return [4 /*yield*/, generateHtmlSynatx(child, templatesLookUp, propDefinitions, stateDefinitions, externals, routeDefinitions, structure)];
case 4:
childTag = _e.sent();
if (!childTag) {
return [2 /*return*/];
}
_i++;
return [3 /*break*/, 1];
case 4: return [4 /*yield*/, generateComponentContent(node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 5:
compTag = _g.sent();
return [2 /*return*/, compTag];
case 6:
elementNode = HASTBuilders.createHTMLNode(elementType);
if (!children) return [3 /*break*/, 10];
_f = 0, children_1 = children;
_g.label = 7;
case 7:
if (!(_f < children_1.length)) return [3 /*break*/, 10];
child = children_1[_f];
return [4 /*yield*/, generateHtmlSyntax(child, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 8:
childTag = _g.sent();
if (typeof childTag === 'string') {

@@ -122,7 +153,7 @@ HASTUtils.addTextNode(elementNode, childTag);

}
_e.label = 5;
case 5:
_i++;
return [3 /*break*/, 3];
case 6:
_g.label = 9;
case 9:
_f++;
return [3 /*break*/, 7];
case 10:
if (Object.keys(referencedStyles).length > 0) {

@@ -140,5 +171,4 @@ Object.keys(referencedStyles).forEach(function (styleRef) {

}
if (Object.keys(attrs).length > 0) {
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions);
}
handleAttributes(elementType, elementNode, attrs, propDefinitions, stateDefinitions, structure.options.projectRouteDefinition, structure.outputOptions);
nodesLookup[key] = elementNode;
return [2 /*return*/, elementNode];

@@ -148,19 +178,21 @@ }

}); };
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, nodesLookup, 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, compName, component, componentClone, compHasSlots, combinedProps, propsForInstance, _i, _e, propKey, combinedStates, statesForInstance, componentWrapper, isExistingNode, componentInstanceToGenerate, compTag, cssPlugin, initialStructure, result, chunk, styleChunk;
var _f, _g, _h;
return __generator(this, function (_j) {
switch (_j.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;
comp = UIDLUtils.cloneObject(externals[elementType] || {});
lookUpTemplates = {};
dependencies = structure.dependencies, _d = structure.chunks, chunks = _d === void 0 ? [] : _d, options = structure.options;
compName = elementType === 'Component' ? 'AppComponent' : elementType;
component = externals[compName];
if (component === undefined) {
throw new HTMLComponentGeneratorError("".concat(compName, " is missing from externals object"));
}
componentClone = UIDLUtils.cloneObject(component);
compHasSlots = false;
if (!comp || !(comp === null || comp === void 0 ? void 0 : comp.node)) {
throw new HTMLComponentGeneratorError("".concat(elementType, " is not found from the externals. \n\n Received ").concat(JSON.stringify(Object.keys(externals), null, 2)));
}
if (children.length) {
compHasSlots = true;
UIDLUtils.traverseNodes(comp.node, function (childNode, parentNode) {
UIDLUtils.traverseNodes(componentClone.node, function (childNode, parentNode) {
var _a, _b;

@@ -193,14 +225,18 @@ if (childNode.type === 'slot' && parentNode.type === 'element') {

}
combinedProps = __assign(__assign({}, propDefinitions), ((comp === null || comp === void 0 ? void 0 : comp.propDefinitions) || {}));
propsForInstance = Object.keys(combinedProps).reduce(function (acc, propKey) {
var _a, _b;
if (attrs[propKey]) {
acc[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: ((_a = attrs[propKey]) === null || _a === void 0 ? void 0 : _a.content) || ((_b = combinedProps[propKey]) === null || _b === void 0 ? void 0 : _b.defaultValue) });
combinedProps = __assign(__assign({}, propDefinitions), ((componentClone === null || componentClone === void 0 ? void 0 : componentClone.propDefinitions) || {}));
propsForInstance = {};
for (_i = 0, _e = Object.keys(combinedProps); _i < _e.length; _i++) {
propKey = _e[_i];
// If the attribute is a named-slot, then we can directly pass the value instead of just the content
if (((_f = attrs[propKey]) === null || _f === void 0 ? void 0 : _f.type) === 'element') {
propsForInstance[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: attrs[propKey] });
}
else if (attrs[propKey]) {
propsForInstance[propKey] = __assign(__assign({}, combinedProps[propKey]), { defaultValue: ((_g = attrs[propKey]) === null || _g === void 0 ? void 0 : _g.content) || ((_h = combinedProps[propKey]) === null || _h === void 0 ? void 0 : _h.defaultValue) });
}
else {
acc[propKey] = combinedProps[propKey];
propsForInstance[propKey] = combinedProps[propKey];
}
return acc;
}, {});
combinedStates = __assign(__assign({}, stateDefinitions), ((comp === null || comp === void 0 ? void 0 : comp.stateDefinitions) || {}));
}
combinedStates = __assign(__assign({}, stateDefinitions), ((componentClone === null || componentClone === void 0 ? void 0 : componentClone.stateDefinitions) || {}));
statesForInstance = Object.keys(combinedStates).reduce(function (acc, propKey) {

@@ -216,37 +252,62 @@ var _a, _b;

}, {});
elementNode = HASTBuilders.createHTMLNode(StringUtils.camelCaseToDashCase(elementType));
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: {
type: 'static',
content: 'contents',
} }) }) }), lookUpTemplates, propsForInstance, statesForInstance, externals, routeDefinitions, structure)];
componentWrapper = StringUtils.camelCaseToDashCase("".concat(compName, "-wrapper"));
isExistingNode = nodesLookup[componentWrapper];
if (isExistingNode !== undefined) {
componentWrapper = "".concat(componentWrapper, "-").concat(StringUtils.generateRandomString());
}
componentInstanceToGenerate = {
type: 'element',
content: {
elementType: componentWrapper,
key: componentWrapper,
children: [componentClone.node],
style: {
display: {
type: 'static',
content: 'contents',
},
},
},
};
return [4 /*yield*/, generateHtmlSyntax(componentInstanceToGenerate, nodesLookup, propsForInstance, statesForInstance, subComponentOptions, structure)];
case 1:
compTag = (_e.sent());
compTag = _j.sent();
cssPlugin = createCSSPlugin({
templateStyle: 'html',
templateChunkName: 'html-template',
templateChunkName: DEFAULT_COMPONENT_CHUNK_NAME,
declareDependency: 'import',
forceScoping: true,
chunkName: comp.name,
chunkName: componentClone.name,
staticPropReferences: 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({}, componentClone), { propDefinitions: propsForInstance, stateDefinitions: statesForInstance }),
chunks: [
{
type: ChunkType.HAST,
fileType: FileType.HTML,
name: DEFAULT_COMPONENT_CHUNK_NAME,
linkAfter: [],
content: compTag,
meta: {
nodesLookup: nodesLookup,
},
],
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 = _j.sent();
if (compHasSlots) {

@@ -260,8 +321,12 @@ result.chunks.forEach(function (chunk) {

else {
chunk = chunks.find(function (item) { return item.name === comp.name; });
chunk = chunks.find(function (item) { return item.name === componentClone.name; });
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);
}
}
nodesLookup[key] = compTag;
return [2 /*return*/, compTag];

@@ -271,10 +336,26 @@ }

}); };
var generateDynamicNode = function (node, _, propDefinitions, stateDefinitions) {
var spanTag = HASTBuilders.createHTMLNode('span');
var usedReferenceValue = node.content.referenceType === 'prop'
? getValueFromReference(node.content.id, propDefinitions)
: getValueFromReference(node.content.id, stateDefinitions);
HASTUtils.addTextNode(spanTag, String(usedReferenceValue));
return spanTag;
};
var generateDynamicNode = function (node, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure) { return __awaiter(void 0, void 0, void 0, function () {
var usedReferenceValue, slotNode, spanTagWrapper, commentNode, spanTag;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
usedReferenceValue = getValueFromReference(node.content.id, node.content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
if (!(usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue)) return [3 /*break*/, 2];
return [4 /*yield*/, generateElementNode(usedReferenceValue.defaultValue, nodesLookup, propDefinitions, stateDefinitions, subComponentOptions, structure)];
case 1:
slotNode = _a.sent();
return [2 /*return*/, slotNode];
case 2:
if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue === undefined) {
spanTagWrapper = HASTBuilders.createHTMLNode('span');
commentNode = HASTBuilders.createComment("Content for slot ".concat(node.content.id));
HASTUtils.addChildNode(spanTagWrapper, commentNode);
return [2 /*return*/, spanTagWrapper];
}
spanTag = HASTBuilders.createHTMLNode('span');
HASTUtils.addTextNode(spanTag, String(usedReferenceValue.defaultValue));
return [2 /*return*/, spanTag];
}
});
}); };
var handleStyles = function (node, styles, propDefinitions, stateDefinitions) {

@@ -285,8 +366,6 @@ Object.keys(styles).forEach(function (styleKey) {

if (style.type === 'dynamic' && ((_a = style.content) === null || _a === void 0 ? void 0 : _a.referenceType) !== 'token') {
if (style.content.referenceType === 'prop') {
style = getValueFromReference(style.content.id, propDefinitions);
var referencedValue = getValueFromReference(style.content.id, style.content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
if (referencedValue.type === 'string' || referencedValue.type === 'number') {
style = String(referencedValue.defaultValue);
}
else if (style.content.referenceType === 'state') {
style = getValueFromReference(style.content.id, stateDefinitions);
}
node.content.style[styleKey] = typeof style === 'string' ? staticNode(style) : style;

@@ -296,38 +375,81 @@ }

};
var handleAttributes = function (htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions) {
Object.keys(attrs).forEach(function (attrKey) {
var handleAttributes = function (elementType, htmlNode, attrs, propDefinitions, stateDefinitions, routeDefinitions, outputOptions) {
var _loop_1 = function (attrKey) {
var attrValue = attrs[attrKey];
if (attrKey === 'href' &&
attrValue.type === 'static' &&
typeof attrValue.content === 'string' &&
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));
return;
var type = attrValue.type, content = attrValue.content;
switch (type) {
case 'static': {
if (attrKey === 'href' && typeof content === 'string' && content.startsWith('/')) {
var targetLink = void 0;
var targetRoute = ((routeDefinitions === null || routeDefinitions === void 0 ? void 0 : routeDefinitions.values) || []).find(function (route) { return route.pageOptions.navLink === content; });
if (targetRoute) {
targetLink = targetRoute.pageOptions.navLink;
}
if (!targetRoute && content === '/home') {
targetLink = '/';
}
if (!targetLink && !targetRoute) {
targetLink = 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"));
break;
}
if (typeof content === 'boolean') {
htmlNode.properties[attrKey] = content === true ? 'true' : 'false';
}
else if (typeof content === 'string' || typeof attrValue.content === 'number') {
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);
}
break;
}
case 'dynamic': {
var value = getValueFromReference(content.id, content.referenceType === 'prop' ? propDefinitions : stateDefinitions);
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value.defaultValue));
break;
}
case 'raw': {
HASTUtils.addAttributeToNode(htmlNode, attrKey, content);
break;
}
case 'element':
case 'import':
case 'expr':
break;
default: {
throw new HTMLComponentGeneratorError("Received ".concat(JSON.stringify(attrValue, null, 2), " \n in handleAttributes for html"));
}
}
if (attrValue.type === 'dynamic') {
var value = attrValue.content.referenceType === 'prop'
? getValueFromReference(attrValue.content.id, propDefinitions)
: getValueFromReference(attrValue.content.id, stateDefinitions);
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value));
return;
}
if (attrValue.type === 'raw') {
HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content);
return;
}
if (typeof attrValue.content === 'boolean') {
HASTUtils.addBooleanAttributeToNode(htmlNode, attrKey);
return;
}
else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') {
HASTUtils.addAttributeToNode(htmlNode, attrKey, StringUtils.encode(String(attrValue.content)));
return;
}
});
};
for (var _i = 0, _a = Object.keys(attrs); _i < _a.length; _i++) {
var attrKey = _a[_i];
_loop_1(attrKey);
}
};

@@ -339,10 +461,11 @@ var getValueFromReference = function (key, definitions) {

}
if (!usedReferenceValue.hasOwnProperty('defaultValue')) {
if (['string', 'number', 'object', 'element'].includes(usedReferenceValue === null || usedReferenceValue === void 0 ? void 0 : usedReferenceValue.type) === false) {
throw new HTMLComponentGeneratorError("Attribute is using dynamic value, but received of type ".concat(JSON.stringify(usedReferenceValue, null, 2)));
}
if (usedReferenceValue.type !== 'element' &&
usedReferenceValue.hasOwnProperty('defaultValue') === false) {
throw new HTMLComponentGeneratorError("Default value is missing from dynamic reference - ".concat(JSON.stringify(usedReferenceValue, null, 2)));
}
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)));
}
return String(usedReferenceValue.defaultValue);
return usedReferenceValue;
};
//# sourceMappingURL=node-handlers.js.map
{
"name": "@teleporthq/teleport-plugin-html-base-component",
"version": "0.34.0-alpha.0",
"version": "0.34.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.34.0-alpha.0",
"@teleporthq/teleport-plugin-css": "^0.34.0-alpha.0",
"@teleporthq/teleport-shared": "^0.34.0-alpha.0",
"@teleporthq/teleport-types": "^0.34.0-alpha.0",
"@teleporthq/teleport-uidl-builders": "^0.34.0-alpha.0"
"@teleporthq/teleport-plugin-common": "^0.34.0",
"@teleporthq/teleport-plugin-css": "^0.34.0",
"@teleporthq/teleport-shared": "^0.34.0",
"@teleporthq/teleport-types": "^0.34.0",
"@teleporthq/teleport-uidl-builders": "^0.34.0"
},
"gitHead": "89e99b8d79cd3895febd6ba5cd26499c8e743e16"
"gitHead": "e96dd1dda3eebc0a845b2ede19f057702170f0d8"
}

@@ -1,1 +0,1 @@

export const DEFAULT_COMPONENT_CHUNK_NAME = 'html-template'
export const DEFAULT_COMPONENT_CHUNK_NAME = 'html-chunk'

@@ -8,6 +8,8 @@ import {

ComponentUIDL,
HastText,
UIDLElementNode,
} from '@teleporthq/teleport-types'
import { HASTBuilders, HASTUtils } from '@teleporthq/teleport-plugin-common'
import { DEFAULT_COMPONENT_CHUNK_NAME } from './constants'
import { generateHtmlSynatx } from './node-handlers'
import { generateHtmlSyntax } from './node-handlers'
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'

@@ -22,3 +24,3 @@

htmlComponentPlugin: ComponentPlugin
addExternals: (list: Record<string, ComponentUIDL>) => void
addExternals: (list: Record<string, ComponentUIDL>, plugins: ComponentPlugin[]) => void
}

@@ -31,4 +33,8 @@

let externals: Record<string, ComponentUIDL> = {}
let plugins: ComponentPlugin[] = []
const addExternals = (list?: Record<string, ComponentUIDL>) => {
const addExternals = (
list?: Record<string, ComponentUIDL>,
subComponentPlugins: ComponentPlugin[] = []
) => {
externals = {

@@ -38,9 +44,10 @@ ...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
const templatesLookUp: Record<string, unknown> = {}
const nodesLookup: Record<string, HastNode | HastText> = {}
const compBase = wrapComponent

@@ -50,17 +57,48 @@ ? HASTBuilders.createHTMLNode('body')

const bodyContent = await generateHtmlSynatx(
const subComponents = {
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,
}
const templateOptions = { chunks, dependencies, options, outputOptions }
/*
We need to generate jsx structure of every node that is defined in the UIDL.
If we use these nodes in the later stage of the code-generation depends on the usage of these nodes.
*/
for (const propKey of Object.keys(propDefinitions)) {
const prop = propDefinitions[propKey]
if (
prop.type === 'element' &&
prop.defaultValue !== undefined &&
typeof prop.defaultValue === 'object'
) {
await generateHtmlSyntax(
prop.defaultValue as UIDLElementNode,
nodesLookup,
propDefinitions,
stateDefinitions,
subComponents,
templateOptions
)
}
}
const bodyContent = await generateHtmlSyntax(
uidl.node,
templatesLookUp,
nodesLookup,
propDefinitions,
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 }
subComponents,
templateOptions
)
HASTUtils.addChildNode(compBase, bodyContent as HastNode)

@@ -75,3 +113,3 @@

meta: {
nodesLookup: templatesLookUp,
nodesLookup,
},

@@ -78,0 +116,0 @@ })

@@ -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,9 +33,21 @@ 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> = (
node: NodeType,
templatesLookUp: Record<string, unknown>,
nodesLookup: Record<string, HastNode | HastText>,
propDefinitions: Record<string, UIDLPropDefinition>,
stateDefinitions: Record<string, UIDLStateDefinition>,
externals: Record<string, ComponentUIDL>,
routeDefinitions: UIDLRouteDefinitions,
subComponentOptions: {
externals: Record<string, ComponentUIDL>
plugins: ComponentPlugin[]
},
structure: {

@@ -40,12 +57,12 @@ chunks: ChunkDefinition[]

options: GeneratorOptions
outputOptions: UIDLComponentOutputOptions
}
) => ReturnType
export const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastText>> = async (
export const generateHtmlSyntax: NodeToHTML<UIDLNode, Promise<HastNode | HastText>> = async (
node,
templatesLookUp,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure

@@ -65,23 +82,24 @@ ) => {

case 'element':
return generatElementNode(
const elementNode = await generateElementNode(
node,
templatesLookUp,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure
)
return elementNode
case 'dynamic':
return generateDynamicNode(
const dynamicNode = await generateDynamicNode(
node,
templatesLookUp,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure
)
return dynamicNode
default:

@@ -98,9 +116,8 @@ throw new HTMLComponentGeneratorError(

const generatElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastText>> = async (
const generateElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastText>> = async (
node,
templatesLookUp,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure

@@ -117,6 +134,2 @@ ) => {

} = node.content
const elementNode = HASTBuilders.createHTMLNode(elementType)
templatesLookUp[key] = elementNode
const { dependencies } = structure

@@ -128,29 +141,41 @@ if (dependency && (dependency as UIDLDependency)?.type !== 'local') {

if (dependency && (dependency as UIDLDependency)?.type === 'local') {
for (const attrKey of Object.keys(attrs)) {
const attr = attrs[attrKey]
if (attr.type === 'element') {
await generateElementNode(
attr,
nodesLookup,
propDefinitions,
stateDefinitions,
subComponentOptions,
structure
)
}
}
const compTag = await generateComponentContent(
node,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure
)
return compTag
}
const elementNode = HASTBuilders.createHTMLNode(elementType)
if (children) {
for (const child of children) {
const childTag = await generateHtmlSynatx(
const childTag = await generateHtmlSyntax(
child,
templatesLookUp,
nodesLookup,
propDefinitions,
stateDefinitions,
externals,
routeDefinitions,
subComponentOptions,
structure
)
if (!childTag) {
return
}
if (typeof childTag === 'string') {

@@ -178,6 +203,13 @@ HASTUtils.addTextNode(elementNode, childTag)

if (Object.keys(attrs).length > 0) {
handleAttributes(elementNode, attrs, propDefinitions, stateDefinitions, routeDefinitions)
}
handleAttributes(
elementType,
elementNode,
attrs,
propDefinitions,
stateDefinitions,
structure.options.projectRouteDefinition,
structure.outputOptions
)
nodesLookup[key] = elementNode
return elementNode

@@ -188,6 +220,9 @@ }

node: UIDLElementNode,
nodesLookup: Record<string, HastNode | HastText>,
propDefinitions: Record<string, UIDLPropDefinition>,
stateDefinitions: Record<string, UIDLStateDefinition>,
externals: Record<string, ComponentUIDL>,
routeDefinitions: UIDLRouteDefinitions,
subComponentOptions: {
externals: Record<string, ComponentUIDL>
plugins: ComponentPlugin[]
},
structure: {

@@ -197,18 +232,21 @@ chunks: ChunkDefinition[]

options: GeneratorOptions
outputOptions: UIDLComponentOutputOptions
}
) => {
const { externals, plugins } = subComponentOptions
const { elementType, attrs = {}, key, children = [] } = node.content
const { dependencies, chunks, options } = structure
const comp = UIDLUtils.cloneObject(externals[elementType] || {}) as ComponentUIDL
const lookUpTemplates: Record<string, unknown> = {}
const { dependencies, chunks = [], options } = structure
// "Component" will not exist when generating a component because the resolver checks for illegal class names
const compName = elementType === 'Component' ? 'AppComponent' : elementType
const component = externals[compName]
if (component === undefined) {
throw new HTMLComponentGeneratorError(`${compName} is missing from externals object`)
}
const componentClone = UIDLUtils.cloneObject(component) as ComponentUIDL
let compHasSlots: boolean = false
if (!comp || !comp?.node) {
throw new HTMLComponentGeneratorError(`${elementType} is not found from the externals. \n
Received ${JSON.stringify(Object.keys(externals), null, 2)}`)
}
if (children.length) {
compHasSlots = true
UIDLUtils.traverseNodes(comp.node, (childNode, parentNode) => {
UIDLUtils.traverseNodes(componentClone.node, (childNode, parentNode) => {
if (childNode.type === 'slot' && parentNode.type === 'element') {

@@ -242,21 +280,23 @@ const nonSlotNodes = parentNode.content?.children?.filter((n) => n.type !== 'slot')

const combinedProps = { ...propDefinitions, ...(comp?.propDefinitions || {}) }
const combinedProps = { ...propDefinitions, ...(componentClone?.propDefinitions || {}) }
const propsForInstance: Record<string, UIDLPropDefinition> = {}
const propsForInstance = Object.keys(combinedProps).reduce(
(acc: Record<string, UIDLPropDefinition>, propKey) => {
if (attrs[propKey]) {
acc[propKey] = {
...combinedProps[propKey],
defaultValue: attrs[propKey]?.content || combinedProps[propKey]?.defaultValue,
}
} else {
acc[propKey] = combinedProps[propKey]
for (const propKey of Object.keys(combinedProps)) {
// If the attribute is a named-slot, then we can directly pass the value instead of just the content
if (attrs[propKey]?.type === 'element') {
propsForInstance[propKey] = {
...combinedProps[propKey],
defaultValue: attrs[propKey],
}
} else if (attrs[propKey]) {
propsForInstance[propKey] = {
...combinedProps[propKey],
defaultValue: attrs[propKey]?.content || combinedProps[propKey]?.defaultValue,
}
} else {
propsForInstance[propKey] = combinedProps[propKey]
}
}
return acc
},
{}
)
const combinedStates = { ...stateDefinitions, ...(comp?.stateDefinitions || {}) }
const combinedStates = { ...stateDefinitions, ...(componentClone?.stateDefinitions || {}) }
const statesForInstance = Object.keys(combinedStates).reduce(

@@ -278,39 +318,44 @@ (acc: Record<string, UIDLStateDefinition>, propKey) => {

const elementNode = HASTBuilders.createHTMLNode(StringUtils.camelCaseToDashCase(elementType))
lookUpTemplates[key] = elementNode
let componentWrapper = StringUtils.camelCaseToDashCase(`${compName}-wrapper`)
const isExistingNode = nodesLookup[componentWrapper]
if (isExistingNode !== undefined) {
componentWrapper = `${componentWrapper}-${StringUtils.generateRandomString()}`
}
const compTag = (await generateHtmlSynatx(
{
...comp.node,
content: {
...comp.node.content,
style: {
...(comp.node.content?.style || {}),
display: {
type: 'static',
content: 'contents',
},
const componentInstanceToGenerate: UIDLElementNode = {
type: 'element',
content: {
elementType: componentWrapper,
key: componentWrapper,
children: [componentClone.node],
style: {
display: {
type: 'static',
content: 'contents',
},
},
},
lookUpTemplates,
}
const compTag = await generateHtmlSyntax(
componentInstanceToGenerate,
nodesLookup,
propsForInstance,
statesForInstance,
externals,
routeDefinitions,
subComponentOptions,
structure
)) as unknown as HastNode
)
const cssPlugin = createCSSPlugin({
templateStyle: 'html',
templateChunkName: 'html-template',
templateChunkName: DEFAULT_COMPONENT_CHUNK_NAME,
declareDependency: 'import',
forceScoping: true,
chunkName: comp.name,
chunkName: componentClone.name,
staticPropReferences: true,
})
const result = await cssPlugin({
const initialStructure: ComponentStructure = {
uidl: {
...comp,
...componentClone,
propDefinitions: propsForInstance,

@@ -327,3 +372,3 @@ stateDefinitions: statesForInstance,

meta: {
nodesLookup: lookUpTemplates,
nodesLookup,
},

@@ -334,4 +379,12 @@ },

options,
})
}
const result = await [cssPlugin, ...plugins].reduce(
async (previousPluginOperation: Promise<ComponentStructure>, plugin) => {
const modifiedStructure = await previousPluginOperation
return plugin(modifiedStructure)
},
Promise.resolve(initialStructure)
)
if (compHasSlots) {

@@ -344,5 +397,10 @@ result.chunks.forEach((chunk) => {

} else {
const chunk = chunks.find((item) => item.name === comp.name)
const chunk = chunks.find((item) => item.name === componentClone.name)
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)

@@ -352,18 +410,41 @@ }

nodesLookup[key] = compTag
return compTag
}
const generateDynamicNode: NodeToHTML<UIDLDynamicReference, HastNode> = (
const generateDynamicNode: NodeToHTML<UIDLDynamicReference, Promise<HastNode>> = async (
node,
_,
nodesLookup,
propDefinitions,
stateDefinitions
) => {
stateDefinitions,
subComponentOptions,
structure
): Promise<HastNode> => {
const usedReferenceValue = getValueFromReference(
node.content.id,
node.content.referenceType === 'prop' ? propDefinitions : stateDefinitions
)
if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue) {
const slotNode = await generateElementNode(
usedReferenceValue.defaultValue as UIDLElementNode,
nodesLookup,
propDefinitions,
stateDefinitions,
subComponentOptions,
structure
)
return slotNode as HastNode
}
if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue === undefined) {
const spanTagWrapper = HASTBuilders.createHTMLNode('span')
const commentNode = HASTBuilders.createComment(`Content for slot ${node.content.id}`)
HASTUtils.addChildNode(spanTagWrapper, commentNode)
return spanTagWrapper
}
const spanTag = HASTBuilders.createHTMLNode('span')
const usedReferenceValue =
node.content.referenceType === 'prop'
? getValueFromReference(node.content.id, propDefinitions)
: getValueFromReference(node.content.id, stateDefinitions)
HASTUtils.addTextNode(spanTag, String(usedReferenceValue))
HASTUtils.addTextNode(spanTag, String(usedReferenceValue.defaultValue))
return spanTag

@@ -381,6 +462,8 @@ }

if (style.type === 'dynamic' && style.content?.referenceType !== 'token') {
if (style.content.referenceType === 'prop') {
style = getValueFromReference(style.content.id, propDefinitions)
} else if (style.content.referenceType === 'state') {
style = getValueFromReference(style.content.id, stateDefinitions)
const referencedValue = getValueFromReference(
style.content.id,
style.content.referenceType === 'prop' ? propDefinitions : stateDefinitions
)
if (referencedValue.type === 'string' || referencedValue.type === 'number') {
style = String(referencedValue.defaultValue)
}

@@ -393,2 +476,3 @@ node.content.style[styleKey] = typeof style === 'string' ? staticNode(style) : style

const handleAttributes = (
elementType: UIDLElement['elementType'],
htmlNode: HastNode,

@@ -398,47 +482,104 @@ attrs: Record<string, UIDLAttributeValue>,

stateDefinitions: Record<string, UIDLStateDefinition>,
routeDefinitions: UIDLRouteDefinitions
routeDefinitions: UIDLRouteDefinitions,
outputOptions: UIDLComponentOutputOptions
) => {
Object.keys(attrs).forEach((attrKey) => {
let attrValue = attrs[attrKey]
for (const attrKey of Object.keys(attrs)) {
const attrValue = attrs[attrKey]
const { type, content } = attrValue
if (
attrKey === 'href' &&
attrValue.type === 'static' &&
typeof attrValue.content === 'string' &&
attrValue.content.startsWith('/')
) {
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))
return
}
switch (type) {
case 'static': {
if (attrKey === 'href' && typeof content === 'string' && content.startsWith('/')) {
let targetLink
if (attrValue.type === 'dynamic') {
const value =
attrValue.content.referenceType === 'prop'
? getValueFromReference(attrValue.content.id, propDefinitions)
: getValueFromReference(attrValue.content.id, stateDefinitions)
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value))
return
}
const targetRoute = (routeDefinitions?.values || []).find(
(route) => route.pageOptions.navLink === content
)
if (attrValue.type === 'raw') {
HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content)
return
}
if (targetRoute) {
targetLink = targetRoute.pageOptions.navLink
}
if (typeof attrValue.content === 'boolean') {
HASTUtils.addBooleanAttributeToNode(htmlNode, attrKey)
return
} else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') {
HASTUtils.addAttributeToNode(htmlNode, attrKey, StringUtils.encode(String(attrValue.content)))
return
if (!targetRoute && content === '/home') {
targetLink = '/'
}
if (!targetLink && !targetRoute) {
targetLink = content
}
const currentPageRoute = join(...(outputOptions?.folderPath || []), './')
const localPrefix = relative(
`/${currentPageRoute}`,
`/${targetLink === '/' ? 'index' : targetLink}`
)
HASTUtils.addAttributeToNode(htmlNode, attrKey, `${localPrefix}.html`)
break
}
if (typeof content === 'boolean') {
htmlNode.properties[attrKey] = content === true ? 'true' : 'false'
} else if (typeof content === 'string' || typeof attrValue.content === 'number') {
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)
}
break
}
case 'dynamic': {
const value = getValueFromReference(
content.id,
content.referenceType === 'prop' ? propDefinitions : stateDefinitions
)
HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value.defaultValue))
break
}
case 'raw': {
HASTUtils.addAttributeToNode(htmlNode, attrKey, content)
break
}
case 'element':
case 'import':
case 'expr':
break
default: {
throw new HTMLComponentGeneratorError(
`Received ${JSON.stringify(attrValue, null, 2)} \n in handleAttributes for html`
)
}
}
})
}
}

@@ -449,3 +590,3 @@

definitions: Record<string, UIDLPropDefinition>
): string => {
): UIDLPropDefinition | undefined => {
const usedReferenceValue = definitions[key.includes('.') ? key.split('.')[0] : key]

@@ -459,5 +600,5 @@

if (!usedReferenceValue.hasOwnProperty('defaultValue')) {
if (['string', 'number', 'object', 'element'].includes(usedReferenceValue?.type) === false) {
throw new HTMLComponentGeneratorError(
`Default value is missing from dynamic reference - ${JSON.stringify(
`Attribute is using dynamic value, but received of type ${JSON.stringify(
usedReferenceValue,

@@ -470,5 +611,8 @@ null,

if (!['string', 'number', 'object'].includes(usedReferenceValue?.type)) {
if (
usedReferenceValue.type !== 'element' &&
usedReferenceValue.hasOwnProperty('defaultValue') === false
) {
throw new HTMLComponentGeneratorError(
`Attribute is using dynamic value, but received of type ${JSON.stringify(
`Default value is missing from dynamic reference - ${JSON.stringify(
usedReferenceValue,

@@ -481,3 +625,3 @@ null,

return String(usedReferenceValue.defaultValue)
return usedReferenceValue
}

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc