Skip to content

Commit

Permalink
Merge pull request #15 from InDIOS/development
Browse files Browse the repository at this point in the history
Bump to version 0.3.2
  • Loading branch information
InDIOS authored Oct 31, 2018
2 parents c75adc4 + a8bebfb commit 708eb06
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 81 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
0.3.2
- Added slot function helper.
- Refactored slot elements generation.
- Fixed issue with 'name' as global.

0.3.1
- Fixed missing hook prefixes.
- Fixed issue with transition to trebor-tools module.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "trebor",
"version": "0.3.1",
"version": "0.3.2",
"description": "A node js module to make standalone web components.",
"main": "./build/index.js",
"bin": {
Expand Down
8 changes: 1 addition & 7 deletions src/generators/bindings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ctx } from '../utilities/context';
import { BlockAreas } from '../utilities/classes';
import { capitalize, filterParser } from '../utilities/tools';
import { capitalize, filterParser, toMap } from '../utilities/tools';

const isBooleanAttr = toMap(`allowfullscreen,async,autofocus,autoplay,checked,compact,controls,
declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,
Expand Down Expand Up @@ -37,9 +37,3 @@ export function genBind(variable: string, attr: string, expression: string, area
}
!isSelMulti && !isBooleanAttr(attr) && areas.update.push(`_$bindUpdate(${variable}, ${bindFunc});`);
}

function toMap(str: string) {
const map: Record<string, boolean> = str
.split(',').reduce((map, val) => (map[val.trim()] = 1, map), {});
return (val: string) => !!map[val];
}
117 changes: 60 additions & 57 deletions src/generators/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { ctx } from '../utilities/context';
import { genSetAttrs } from './attributes';
import { genDirective } from './directives';
import { NodeElement, BlockAreas } from '../utilities/classes';
import { kebabToCamelCases, getVarName, capitalize, createElement, filterParser } from '../utilities/tools';
import { kebabToCamelCases, getVarName, capitalize, createElement, filterParser, toMap } from '../utilities/tools';

const buildinDirective = toMap(`for,if,value,name,show,html`);

export function genTag(node: NodeElement, areas: BlockAreas, scope: string) {
[scope] = scope.split(',');
Expand All @@ -19,7 +21,7 @@ export function genTag(node: NodeElement, areas: BlockAreas, scope: string) {
const setTag = `${setElement}(${scope}${params})`;
areas.extras.push(`${setElement} = (${scope}${params}) => ${code};`);
areas.create.push(`${element} = _$el(${setTag});`);
areas.update.push(`${element} = _$tagUpdate(${element}, ${setTag});`);
areas.update.push(`${element} = _$tagUpdate(${element}, ${setTag});`);
} else {
element = getVarName(areas.variables, node.tagName);
}
Expand All @@ -28,19 +30,55 @@ export function genTag(node: NodeElement, areas: BlockAreas, scope: string) {

export function genSlot(node: NodeElement, areas: BlockAreas, scope: string) {
const slotName = node.getAttribute('name') || 'default';
const slot = `${scope.split(', ')[0]}.$slots['${slotName}']`;
areas.extras.push(`${slot} = _$docFragment();`);
const slot = `_$slots`;
const slotDec = `${slot}['${slotName}']`;
const init = `const ${slot} = ${scope.split(', ')[0]}.$slots;`;
!areas.extras.includes(init) && areas.extras.push(init);
let dec = areas.extras.find(extra => extra.startsWith('_$declareSlots(_$slots, ['));
if (dec) {
let index = areas.extras.indexOf(dec);
dec = dec.replace(']);', `, '${slotName}']);`);
areas.extras.splice(index, 1, dec);
} else {
areas.extras.push(`_$declareSlots(${slot}, ['${slotName}']);`);
}
const roots: string[] = [];
node.childNodes.forEach(n => {
const el = genBlockAreas(n, areas, scope);
if (el) {
roots.push(el);
areas.unmount.push(`_$append(${slot}, ${el});`);
areas.unmount.push(`_$appendToSlot(${slot}, '${slotName}', ${el});`);
}
});
const parent = node.parentElement;
let root = parent.dymTag ? parent.dymTag : parent.varName;
areas.unmount.push(`_$append(${root || '_$frag'}, ${slot});`);
let root = parent.dymTag ? parent.dymTag : parent.varName;
areas.unmount.push(`_$append(${root || '_$frag'}, ${slotDec});`);
}

function genSlotElement(node: NodeElement, areas: BlockAreas, scope: string, variable: string) {
const type = node.nodeType;
if (type !== 8) {
const tag = node.tagName;
const slot = type > 1 ? <string>genBlockAreas(node, areas, scope) : getVarName(areas.variables, tag);
const slotName = node.getAttribute('slot') || 'default';
const slotVar = `${kebabToCamelCases(slotName)}_${variable}`;
const init = `const ${slotVar} = _$emptySlot(${variable}, '${slotName}');`;
!areas.extras.includes(init) && areas.extras.push(init);
if (type === 1) {
if (tag !== 'template') {
areas.create.push(createElement(slot, tag, node.isSVGElement));
} else {
areas.create.push(`${slot} = _$docFragment();`);
node.appendChild(node.content);
}
node.childNodes.forEach(child => {
const el = genBlockAreas(child, areas, scope);
el && areas.unmount.push(`_$append(${slot}, ${el});`);
});
genSetAttrs(slot, node, scope, areas);
}
areas.unmount.push(`${slotVar} && _$append(${slotVar}, ${slot});`);
}
}

export function genComponent(node: NodeElement, areas: BlockAreas, scope: string) {
Expand All @@ -51,7 +89,7 @@ export function genComponent(node: NodeElement, areas: BlockAreas, scope: string
const anchor = getVarName(areas.variables, `${varName}Anchor`);
const variable = getVarName(areas.variables, varName);
const parent = node.parentElement;
let root = parent.dymTag ? parent.dymTag : parent.varName;
let root = parent.dymTag ? parent.dymTag : parent.varName;
let attrs = '{';
const extras: string[] = [];
let isValue: string;
Expand All @@ -69,7 +107,7 @@ export function genComponent(node: NodeElement, areas: BlockAreas, scope: string
areas.destroy.push(`${eventVar}.$off();`);
} else if (name[0] === ':') {
attrs += `${kebabToCamelCases(name.slice(1))}() { return ${ctx(value, scope, params)}; },`;
} else if (name[0] === '$' && !/model|show/.test(name.slice(1))) {
} else if (name[0] === '$' && !buildinDirective(name.slice(1))) {
genDirective(variable, name.slice(1), value, areas, scope);
} else {
attrs += `${kebabToCamelCases(name)}: '${value}'`;
Expand All @@ -80,7 +118,7 @@ export function genComponent(node: NodeElement, areas: BlockAreas, scope: string
let init = `const `;
let setComponent = `set${capitalize(variable)}`;
let setAttrsComponent = `setAttrs${capitalize(variable)}`;
let setComponentCall = `${setComponent}(${isIsAttrExp ? [scope, ...params].join(', ') : ''})`;
let setComponentCall = `${setComponent}(${isIsAttrExp ? [scope, ...params].join(', ') : ''})`;
if (varName === 'component') {
globCompName = capitalize(variable);
areas.variables.push(setComponent, setAttrsComponent);
Expand All @@ -89,66 +127,31 @@ export function genComponent(node: NodeElement, areas: BlockAreas, scope: string
let comp = ${ctx(isValue, scope, areas.globals.concat(params))};
return _$isType(comp, 'string') ? children[comp] : comp;
}` : `() => children['${isValue}']`};`);
init += `${globCompName} = ${setComponentCall};`;
init += `${globCompName} = ${setComponentCall};`;
areas.extras.push(`${init}
${anchor} = _$text();
${variable} = _$addChild(${scope}, ${globCompName}, ${setAttrsComponent}());`);
} else {
init += `${globCompName} = ${varName === 'selfRef' ? `${scope}.constructor` : `children['${tag}'] || window['${globCompName}']`};`;
init += `${globCompName} = ${varName === 'selfRef' ? `${scope}.constructor` : `children['${tag}'] || window.${globCompName}`};`;
!areas.extras.includes(init) && areas.extras.push(init);
areas.extras.push(`${anchor} = _$text();
${variable} = _$addChild(${scope}, ${globCompName}, ${attrs});`);
areas.extras.push(`${anchor} = _$text();
${variable} = _$addChild(${scope}, ${globCompName}, ${attrs});`);
}
areas.create.push(`${variable}.$create();`);
areas.extras = areas.extras.concat(extras);
areas.unmount.push(`_$append(${root || '_$frag'}, ${anchor});`);
node.childNodes.forEach(n => {
let slotName = 'default';
if (n.hasAttribute('slot')) {
slotName = n.getAttribute('slot') || slotName;
}
const slotDec = `${variable}.$slots['${slotName}']`;
const init = `${slotDec} = _$docFragment();`;
if (!areas.extras.includes(init)) {
areas.extras.push(`if (${slotDec} && ${slotDec}.childNodes.length !== 0) {
${init}
}`);
}
if (n.nodeType === 3) {
let slot = genBlockAreas(n, areas, scope);
areas.unmount.push(`if (${slotDec}) {
_$append(${slotDec}, ${slot});
}`);
} else if (n.nodeType === 1) {
const tag = n.tagName;
let slot = getVarName(areas.variables, tag);
if (tag !== 'template') {
areas.create.push(createElement(slot, tag, n.isSVGElement));
} else {
areas.create.push(`${slot} = _$docFragment();`);
n.appendChild(n.content);
}
n.childNodes.forEach(child => {
const el = genBlockAreas(child, areas, scope);
if (el) {
areas.unmount.push(`_$append(${slot}, ${el});`);
}
});
genSetAttrs(slot, n, scope, areas);
areas.unmount.push(`if (${slotDec}) {
_$append(${slotDec}, ${slot});
}`);
}
genSlotElement(n, areas, scope, variable);
});
areas.unmount.push(`${variable}.$mount(${root || '_$frag'}, ${anchor});`);
if (varName === 'component') {
areas.update.push(`[${variable}, ${globCompName}] = _$componentUpdate(${scope},
${globCompName},
${variable},
${setComponentCall},
${setAttrsComponent}(),
${root},
${anchor});`);
areas.update.push(`[${variable}, ${globCompName}] = _$componentUpdate(${scope},
${globCompName},
${variable},
${setComponentCall},
${setAttrsComponent}(),
${root},
${anchor});`);
} else {
areas.update.push(`${variable} && ${variable}.$update();`);
}
Expand Down
15 changes: 8 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import { readFileSync, statSync, writeFile, existsSync } from 'fs';
import { kebabToCamelCases, capitalize, camelToKebabCase } from './utilities/tools';

const dest = `{
_$extend, _$removeChild, _$bindGroup, _$emptyElse, _$Ctor, _$bindMultiSelect, _$setAttr,
_$removeEl, _$assignEl, _$el, _$bindStyle, _$forLoop, _$each, _$insertStyle, _$removeStyle,
_$getAttr, _$addListener, _$updateListener, _$removeListener, _$bindClasses, _$destroyComponent,
_$svg, _$noop, _$toString, _$setReference, _$isType, _$isKey, _$select, _$docFragment, _$append,
_$updateMultiSelect, _$componentUpdate, _$htmlUpdate, _$tagUpdate, _$bindBooleanAttr, _$removeReference,
_$addChild, _$textUpdate, _$getValue, _$text, _$conditionalUpdate, _$bindUpdate, _$comment, _$setElements
_$bindUpdate, _$comment, _$setElements, _$emptySlot, _$appendToSlot, _$declareSlots,
_$updateMultiSelect, _$componentUpdate, _$htmlUpdate, _$tagUpdate, _$bindBooleanAttr,
_$removeReference, _$addChild, _$textUpdate, _$getValue, _$text, _$conditionalUpdate,
_$noop, _$toString, _$setReference, _$isType, _$isKey, _$select, _$docFragment, _$append,
_$removeChild, _$bindGroup, _$emptyElse, _$Ctor, _$bindMultiSelect, _$setAttr, _$removeEl,
_$assignEl, _$el, _$bindStyle, _$forLoop, _$each, _$insertStyle, _$removeStyle, _$getAttr,
_$addListener, _$updateListener, _$removeListener, _$bindClasses, _$destroyComponent, _$svg,
}`;
const esDeps = `import ${dest} from 'trebor-tools';`;
const cjsDeps = `const ${dest} = require('trebor-tools');`;
Expand All @@ -28,7 +29,7 @@ export function genSource(html: string, opts: CompilerOptions) {
if (opts.format === 'es') {
imports.unshift(esDeps);
}
const source = [template, extras, `const ${moduleName} = _$Ctor('${moduleName}', _$tpl${moduleName}, ${options});`]
const source = [template, extras, `const ${moduleName} = _$Ctor(_$tpl${moduleName}, ${options});`]
.filter(c => !!c.length).join('\n');
return { imports, source };
}
Expand Down
2 changes: 1 addition & 1 deletion src/utilities/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ function isDeclared(node: Identifier, { scope }: Path<Node>) {
function isGlobal(node: Identifier, globals = []) {
let { name } = node;
let isGlob = name in builtin || name in browser || name in nodejs || name in amd;
return isGlob || !!~globals.indexOf(name);
return name === 'name' ? false : isGlob || !!~globals.indexOf(name);
}

function isReplaceable(node: Node, path: Path<Node>, globals: string[]) {
Expand Down
6 changes: 6 additions & 0 deletions src/utilities/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export function camelToKebabCase(str: string) {
return kebab;
}

export function toMap(str: string) {
const map: Record<string, boolean> = str
.split(',').reduce((map, val) => (map[val.trim()] = 1, map), {});
return (val: string) => !!map[val];
}

function pad(hash: string, len: number) {
while (hash.length < len) {
hash = `0${hash}`;
Expand Down
5 changes: 5 additions & 0 deletions test/components/comp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div>
<slot name="header"></slot>
<slot>Some text</slot>
<slot name="footer"></slot>
</div>
17 changes: 17 additions & 0 deletions test/components/components.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<comp-inst></comp-inst>
<comp-inst>Some other text</comp-inst>
<comp-inst>
<span>Some span text</span>
<span slot="header">Some header</span>
<span slot="footer">Some footer</span>
</comp-inst>

<script>
/* global Comp */

export default {
children: {
'comp-inst': Comp
}
};
</script>
44 changes: 44 additions & 0 deletions test/src/spec/components.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
describe('Component instance', () => {
let instance;

beforeEach(done => {
instance = new Components();
instance.$mount('main');
done();
});

afterEach(done => {
instance && instance.$destroy();
done();
});

it('should mount all instances', () => {
let main: HTMLInputElement = document.querySelector('main');
expect(main.children.length).toBe(3);
});

it('should be mounted and render the default slot', () => {
let main: HTMLInputElement = document.querySelector('main');
expect(main.firstChild.nodeName).toBe('DIV');
expect(main.firstChild.textContent).toBe('Some text');
});

it('should be mounted and overwrite the default slot', () => {
let main: HTMLInputElement = document.querySelector('main');
let child = main.children[1];
expect(child.nodeName).toBe('DIV');
expect(child.textContent).toBe('Some other text');
});

it('should set the slot correctly', () => {
let main: HTMLInputElement = document.querySelector('main');
let child = main.children[2];
expect(child.nodeName).toBe('DIV');
expect(child.children[0].tagName).toBe('SPAN');
expect(child.children[0].textContent).toBe('Some header');
expect(child.children[1].tagName).toBe('SPAN');
expect(child.children[1].textContent).toBe('Some span text');
expect(child.children[2].tagName).toBe('SPAN');
expect(child.children[2].textContent).toBe('Some footer');
});
});
1 change: 1 addition & 0 deletions test/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ declare const Html: ComponentConstructor;
declare const Init: ComponentConstructor;
declare const Loop: ComponentConstructor;
declare const Condition: ComponentConstructor;
declare const Components: ComponentConstructor;
declare const Interpolation: ComponentConstructor;

declare module 'system' {
Expand Down
Loading

0 comments on commit 708eb06

Please sign in to comment.