Skip to content
This repository has been archived by the owner on Oct 4, 2021. It is now read-only.

Commit

Permalink
feat: add --for flag destructuration
Browse files Browse the repository at this point in the history
  • Loading branch information
SRNV committed Nov 27, 2020
1 parent 0912acb commit 44ee14f
Show file tree
Hide file tree
Showing 21 changed files with 482 additions and 354 deletions.
3 changes: 2 additions & 1 deletion .d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type Style from "./classes/Style";
import type Style from "./classes/css/Style.ts";


export type Environment = "development" | "production" | "staging";
Expand Down Expand Up @@ -400,6 +400,7 @@ export interface ForCtxDescription<T> {
item: string;
array: string;
content: T;
destructured?: string[];
}
export type StyleBundle = {
value: string;
Expand Down
78 changes: 64 additions & 14 deletions classes/ForFlagBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,43 @@ import type {
XMLNodeDescription,
LegacyDescription,
ForCtxDescription,
TypedExpressions,
} from "../.d.ts";
import notParsedElements from '../utils/not-parsed.ts';
import elements from '../utils/elements.ts';
import read from '../utils/agnostic-transformer.ts';
import getTypedExpressions from '../utils/typedExpressions.ts';
import getDeepTranslation from '../utils/template-recursive.ts';

// create a function to get all the properties from a destructuration
// this means that { a } should expose a "a" var
// also a { a: { b } } should expose a "b" var
// also a { a: { b: c } } should expose a "c" var
// and a { a: { b, c = 'c' } } should expose "b" and "c"
function readDestructuration(destructured: string, opts: {
typedExpressions: TypedExpressions;
readonly registry: string[];
}) {
// we will use the saved blocks tokens into typedExpressions
// and save the properties into the registry
const {
typedExpressions,
registry,
} = opts;
if (!typedExpressions.blocks[destructured]) return null;
const content = typedExpressions.blocks[destructured];
const blocks = content.match(/(?<=([\:\=]\s*))\<block\d+\>/gi);
const propertiesRegExp = /(([\w\d]+)+(?=\s*\}$)|(([\w\d]+)+(?=\s*,))|((?<=([\w\d]+)+\s*\:)([\w\d]+)+)|(([\w\d]+)+(?=\s*\=)))/gi;
const properties = content.match(propertiesRegExp);
if (properties) {
registry.push(...properties as string[]);
}
if (blocks) {
blocks.forEach((block: string) => {
readDestructuration(block, opts);
});
}
return true;
}
function* gen(i: number): Generator {
yield i;
while (true) {
Expand Down Expand Up @@ -87,7 +117,7 @@ export default class ForFlagBuilder extends Utils {
const v = node.attributes["--for"];
// get the flags
const oForFlag = this.getForFlagDescription(v as string);
const { item, index, array } = oForFlag;
const { item, index, array, destructured } = oForFlag;
const arrayAlias = `_____a_${arrayAliasIterator.next().value}`;
if (legacy.ctx) {
if (legacy.ctx[item]) {
Expand Down Expand Up @@ -132,12 +162,22 @@ export default class ForFlagBuilder extends Utils {
legacy.getLength = getLengthScript;
// @ts-ignore
legacy.item = item;
let aliasItem;
if (!item.match(/^\w/)) {
aliasItem = `alias_${node.id}`;
// @ts-ignore
legacy.aliasItem = aliasItem;
}
// @ts-ignore
legacy.destructured = destructured;
if (contextLegacy) {
const declarationScript = [`const ${arrayAlias} =
!!${array.split(/(?<!\bthis)(\.)/)[0]}
&& ${array} || [];`, `
let ${index} = POSITION[${contextLegacy.limit}],
${item} = (${arrayAlias})[${index}];`];
${item} = (${arrayAlias})[${index}];`,
aliasItem ? `const ${aliasItem} = (${arrayAlias})[${index}];` : '',
];
if (contextLegacy && contextLegacy.declarationScript) {
contextLegacy.declarationScript = contextLegacy.declarationScript
.concat(declarationScript);
Expand Down Expand Up @@ -189,6 +229,10 @@ export default class ForFlagBuilder extends Utils {
node,
// @ts-ignore
item: legacy.item,
// @ts-ignore
aliasItem: legacy.aliasItem,
// @ts-ignore
destructured: legacy.destructured,
ctx: legacy.ctx,
level: contextLegacy.limit,
getLength: legacy.getLength,
Expand Down Expand Up @@ -216,24 +260,25 @@ export default class ForFlagBuilder extends Utils {
...elements.filter((el) => el.name === 'block'),
],
});
// create a function to return the real value
// the value is transformed by the read function
function deepTranslate(txt: string): string {
return getDeepTranslation(txt, expressions);
}
const itemAndIndexRegExp = /^\((.+?),\s*(\w+?)\)\s+of\s+(.+?)$/gi;
const itemRegExp = /^(.+?)\s+of\s+(.+?)$/gi;
let oForRegExp = itemAndIndexRegExp.exec(flagValue.trim())
const registry: string[] = [];
// if the end user uses: (item, index) of array syntax
if (oForRegExp) {
itemAndIndexRegExp.exec(flagValue.trim());
let [input, item, index, arrayName] = oForRegExp;
readDestructuration(item, {
typedExpressions,
registry,
});
arrayName = flagValue.split("of")[1].trim();
return {
index: index ? index : `i${iterator.next().value}`,
item: deepTranslate(item),
array: deepTranslate(arrayName),
content: deepTranslate(flagValue),
item: getDeepTranslation(item, expressions),
array: getDeepTranslation(arrayName, expressions),
content: getDeepTranslation(flagValue, expressions),
destructured: registry,
};
}
oForRegExp = itemRegExp.exec(flagValue.trim());
Expand All @@ -245,12 +290,17 @@ export default class ForFlagBuilder extends Utils {
}
itemAndIndexRegExp.exec(flagValue.trim());
let [input, item, arrayName] = oForRegExp;
readDestructuration(item, {
typedExpressions,
registry,
});
arrayName = flagValue.split("of")[1].trim();
return {
index: `i${iterator.next().value}`,
item: deepTranslate(item),
array: deepTranslate(arrayName),
content: deepTranslate(flagValue),
item: getDeepTranslation(item, expressions),
array: getDeepTranslation(arrayName, expressions),
content: getDeepTranslation(flagValue, expressions),
destructured: registry,
};
}
}
44 changes: 22 additions & 22 deletions classes/StylesheetBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,6 @@ import Style from './css/Style.ts';
export default class StylesheetBuilder extends Utils {
private CSSScoper: CSSScoper = new CSSScoper();
private Style: Style = new Style();
private readKeyframes(keyframesEvaluated: string) {
const fn = new Function('get', `return (${keyframesEvaluated});`)
const get = (name: string, opts: any) => {
switch (true) {
case typeof name !== 'string':
this.error('using keyframes fade: argument one has to be a string.')
break;
}
return `
.${name} {
animation-name: ${name};
animation-duration: ${opts.time || 1}s;
animation-iteration-count: ${opts.iteration || 1};
animation-fill-mode: ${opts.iteration || 'forwards'};
animation-timing-function: ${opts.style || 'linear'};
}
${keyframes[name]}
`;
};
const k = fn(get);
return Array.isArray(k) ? k.join('\n') : k;
}
async read(bundle: Bundle) {
const entries = Array.from(bundle.components.entries());
for await (const [, component] of entries) {
Expand Down Expand Up @@ -123,4 +101,26 @@ export default class StylesheetBuilder extends Utils {
}
}
}
private readKeyframes(keyframesEvaluated: string) {
const fn = new Function('get', `return (${keyframesEvaluated});`)
const get = (name: string, opts: any) => {
switch (true) {
case typeof name !== 'string':
this.error('using keyframes fade: argument one has to be a string.')
break;
}
return `
.${name} {
animation-name: ${name};
animation-duration: ${opts.time || 1}s;
animation-iteration-count: ${opts.iteration || 1};
animation-fill-mode: ${opts.iteration || 'forwards'};
animation-timing-function: ${opts.style || 'linear'};
}
${keyframes[name]}
`;
};
const k = fn(get);
return Array.isArray(k) ? k.join('\n') : k;
}
}
20 changes: 11 additions & 9 deletions classes/SwitchContextBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default class SwitchContextBuilder extends Utils {
// @ts-ignore
const { script } = flag;
const { modules } = component;
const { node, ctx, getLength, array, item: itemName } = script;
const { node, ctx, getLength, array, item: itemName, aliasItem, destructured } = script;
let contextIf = null;
if (node.attributes && node.attributes["--if"]) {
let nxt = node.nextElementSibling;
Expand Down Expand Up @@ -141,16 +141,21 @@ export default class SwitchContextBuilder extends Utils {
component,
data: component.context.data,
value: script.value || "",
itemName,
itemName: aliasItem || itemName,
context: {
id: `${component.uuid}-${nId}`,
if: contextIf ? contextIf : "",
parentId: node.parentNode
? `${component.uuid}-${node.parentNode.id}`
: "",
result: component.data ? [...Object.keys(ctx), ...Object.keys(component.data)]
.join(',')
.replace(/[\{\}\[\]]/gi, '') : '',
result: component.data ? [
// the key can start with a bracket or a brace
// if the element is destructured
...Object.keys(ctx).filter((key) => !key.match(/^(\{|\[)/)),
...(destructured ? destructured : []),
...Object.keys(component.data)
]
.join(',') : '',
getNodeDynamicLength: isNodeDynamic ? `
if (GET_LENGTH) {
return 1;
Expand All @@ -175,10 +180,7 @@ export default class SwitchContextBuilder extends Utils {
value: script.value || "",
modules: modules ? modules.map((md) => md[0]).join(";\n") : "",
});
bundle.contexts.push(
result.replace(/\n/gi, "")
.replace(/\s+/gi, " "),
);
bundle.contexts.push(result);
});
}
}
Expand Down
36 changes: 36 additions & 0 deletions classes/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { absolute } from '../deps.ts';

export abstract class Utils {
protected getDeepTranslation = getDeepTranslation;
protected static getDeepTranslation = getDeepTranslation;
protected absolute = absolute;
public warn(message: string, opts?: { [k: string]: any }): void {
const { bgYellow, bold, black, yellow } = colors;
Expand All @@ -21,6 +22,18 @@ export abstract class Utils {
) as string;
throw new Error(m);
}
static error(message: string, opts?: { [k: string]: any }): void {
const { bgRed, red, bold, yellow } = colors;
const m: string = this.message(
`${bgRed(" ERROR ")} ${red(message)}\n${
yellow(
`\n\t\tfeeling like it's an issue ?\n\t\tplease report on https://github.com/SRNV/Ogone/issues/new?assignees=&modifiers=&template=bug_report.md&title=`,
)
}`,
{ returns: true },
) as string;
throw new Error(m);
}
public success(message: string, opts?: { [k: string]: any }): void {
const { bgRed, bgBlack, white, bold, green } = colors;
this.message(`${bgBlack(bold(green(" SUCCESS ")))} ${white(message)}`);
Expand Down Expand Up @@ -68,4 +81,27 @@ export abstract class Utils {
}
return result;
}
protected static template(tmpl: string, data: any): string {
let result = tmpl;
const fn = new Function(
"__value",
...Object.keys(data),
`try { return eval('('+ __value + ')'); } catch(err) { throw err; }`,
);
const values = Object.values(data);
while (
result.indexOf("{{") > -1 && result.indexOf("}}") > -1
) {
if (result.indexOf("{{") > result.indexOf("}}")) {
result = result.replace("}}", "} }");
}
const start = result.indexOf("{{");
const end = result.indexOf("}}") + 2;
const substrContent = result.substring(start + 2, end - 2).trim();
const partStart = result.substring(0, start);
const partEnd = result.substring(end);
result = partStart + fn(substrContent, ...values) + partEnd;
}
return result;
}
}
31 changes: 31 additions & 0 deletions classes/css/StyleDocument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Bundle, Component, StyleBundle } from '../../.d.ts';
import { Utils } from '../Utils.ts';

// TODO comments here
export default abstract class StyleDocument extends Utils {
static renderElement(styleBundle: StyleBundle, bundle: Bundle, component: Component): string {
let result = '';
const entries = Array.from(styleBundle.mapDocument.entries())
entries.forEach(([selector, parent]: [string, any]) => {
result += `${selector} { `;
const { childs } = parent;
childs.forEach((item: any) => {
const propsEntries = Object.entries(item.properties.props);
const props = propsEntries.length ? propsEntries.map(([name, value]) => `${name}: ${value};`).join('') : null;
if (props) {
result += `${item.selector} { ${props} } `;
}
});
result += `} `;
});
return result;
}
static saveElement(styleBundle: StyleBundle, bundle: Bundle, component: Component, opts: { item: any }): void {
const { item } = opts;
if (!styleBundle.mapDocument.has(item.isDocument)) styleBundle.mapDocument.set(item.isDocument, { childs: [item] });
else {
const doc = styleBundle.mapDocument.get(item.isDocument);
doc.childs.push(item);
}
}
}
Loading

0 comments on commit 44ee14f

Please sign in to comment.