Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generate TS from HBS templates #6558

Merged
merged 29 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
695fa5f
feat: generate TS from HBS templates
pskelin Feb 14, 2023
4717885
Merge branch 'main' into hbs2ts
pskelin Feb 21, 2023
967af26
chore: cleanup
pskelin Feb 21, 2023
6547c0d
fix: input events and typing
pskelin Feb 22, 2023
22e1c08
fix: tree test failing due to ListItem template
pskelin Feb 22, 2023
d741a6f
chore: cleanup
pskelin Feb 22, 2023
406c81a
fix: base package template build
pskelin Feb 23, 2023
d4c5b9b
Merge branch 'main' into hbs2ts
pskelin Feb 23, 2023
85d89dc
chore: test popover template
pskelin Feb 23, 2023
d8d4d09
Merge branch 'main' into hbs2ts
ilhan007 Feb 28, 2023
22a4b68
chore: remove templ and staticAreaTemp decorators
ilhan007 Feb 28, 2023
8c2fec8
chore: add back component fixes
ilhan007 Feb 28, 2023
a6a095b
chore: change `nnerFocusIn` to be class method
ilhan007 Feb 28, 2023
a24720c
chore: add some JSDoc
ilhan007 Feb 28, 2023
e77bf69
Merge branch 'main' into hbs2ts
pskelin Mar 9, 2023
40f5bb1
build: enable eslint support for VS Code
pskelin Mar 22, 2023
731aac2
Merge branch 'main' into hbs2ts
pskelin Mar 24, 2023
d576a38
chore: cleanup
pskelin Mar 24, 2023
ddf24a3
chore: cleanup
pskelin Mar 27, 2023
81c1147
chore: add TS/JS switch
pskelin Apr 3, 2023
6dbbcaa
Merge branch 'main' into hbs2ts
pskelin Apr 11, 2023
f692562
chore: add types detection
pskelin Apr 11, 2023
dfce1d2
Merge branch 'main' into hbs2ts
pskelin Apr 20, 2023
1137bf5
chore: type
pskelin Apr 21, 2023
dfea69c
chore: turn on checking and fix errors
pskelin May 3, 2023
6871714
Merge branch 'main' into hbs2ts
pskelin May 3, 2023
a13235d
chore: fix test
pskelin May 3, 2023
97be803
chore: remove global module definitions of .lit.js
pskelin May 4, 2023
cb15e8d
Merge branch 'main' into hbs2ts
pskelin May 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: add TS/JS switch
  • Loading branch information
pskelin committed Apr 3, 2023
commit 81c114721a341496c139b51e430e57712497b690
2 changes: 1 addition & 1 deletion packages/base/package-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const scripts = {
generateAssetParameters: `node "${assetParametersScript}"`,
generateVersionInfo: `node "${versionScript}"`,
generateStyles: `node "${stylesScript}"`,
generateTemplates: `mkdirp src/generated/templates && cross-env UI5_BASE=true node "${LIB}/hbs2ui5/index.js" -d test/elements -o src/generated/templates`,
generateTemplates: `mkdirp src/generated/templates && cross-env UI5_BASE=true UI5_TS=true node "${LIB}/hbs2ui5/index.js" -d test/elements -o src/generated/templates`,
generateAPI: {
default: "nps generateAPI.prepare generateAPI.preprocess generateAPI.jsdoc generateAPI.cleanup",
prepare: `copy-and-watch "dist/**/*.js" jsdoc-dist/`,
Expand Down
2 changes: 1 addition & 1 deletion packages/tools/components-package/nps.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const getScripts = (options) => {
typescript: tsCommand,
build: {
default: "nps prepare lint build.bundle",
templates: `mkdirp dist/generated/templates && node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates`,
templates: `mkdirp dist/generated/templates && ${tsCrossEnv} node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates`,
styles: {
default: `nps build.styles.themes build.styles.components ${copySrcGenerated}`,
themes: `node "${LIB}/postcss-p/postcss-p.mjs"`,
Expand Down
4 changes: 3 additions & 1 deletion packages/tools/lib/hbs2lit/src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ const hbs2lit = async (file, componentName) => {

sPreprocessed = removeWhiteSpaces(sPreprocessed);

const blockSignature = process.env.UI5_TS ? `this: ${componentName}` : ""

// icons hack
if (sPreprocessed.startsWith("<g ") || sPreprocessed.startsWith("<g>")) {
return `
function block0 (this: ${componentName}) {
function block0 (${blockSignature}) {
return svg\`${sPreprocessed}\`
}`;
}
Expand Down
50 changes: 34 additions & 16 deletions packages/tools/lib/hbs2lit/src/litVisitor2.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ function HTMLLitVisitor(componentName, debug) {
this.result = "";
this.mainBlock = "";
this.blockLevel = 0;
this.blockParametersDefinition = ["context: UI5Element", "tags: string[]", "suffix: string | undefined"];
this.blockParametersUsage = ["context", "tags", "suffix"];
this.paths = []; //contains all normalized relative paths
this.componentName = componentName
const blockParametersDefinitionTS = [`this: ${componentName}`, "context: UI5Element", "tags: string[]", "suffix: string | undefined"];
const blockParametersDefinitionJS = ["context", "tags", "suffix"];
this.blockParametersDefinition = process.env.UI5_TS ? blockParametersDefinitionTS : blockParametersDefinitionJS;
this.blockParametersUsage = ["this", "context", "tags", "suffix"];
this.paths = []; //contains all normalized relative paths
this.debug = debug;
if (this.debug) {
this.blockByNumber = [];
Expand All @@ -54,10 +56,10 @@ HTMLLitVisitor.prototype.Program = function(program) {
this.debug && this.blockByNumber.push(key);

// this.blocks[this.currentKey()] = "function " + this.currentKey() + ` (this: any, ` + this.blockParametersDefinition.join(", ") + ") { ";
this.blocks[this.currentKey()] = "function " + this.currentKey() + ` (this: ${this.componentName}, ` + this.blockParametersDefinition.join(", ") + ") { ";
this.blocks[this.currentKey()] = `function ${this.currentKey()} (${this.blockParametersDefinition.join(", ")}) { `;

if (this.keys.length > 1) { //it's a nested block
this.blocks[this.prevKey()] += this.currentKey() + ".call(this, " + this.blockParametersUsage.join(", ") + ")";
this.blocks[this.prevKey()] += this.currentKey() + ".call(" + this.blockParametersUsage.join(", ") + ")";
} else {
this.mainBlock = this.currentKey();
}
Expand Down Expand Up @@ -108,7 +110,11 @@ HTMLLitVisitor.prototype.MustacheStatement = function(mustache) {
if (isNodeValue && !mustache.escaped) {
parsedCode = `\${unsafeHTML(${path})}`;
} else if (hasCalculatingClasses) {
parsedCode = `\${classMap(${path} as ClassMapValue)}`;
if (process.env.UI5_TS) {
parsedCode = `\${classMap(${path} as ClassMapValue)}`;
} else {
parsedCode = `\${classMap(${path})}`;
}
} else if (isStyleAttribute) {
parsedCode = `\${styleMap(${path})}`;
} else if (skipIfDefined){
Expand Down Expand Up @@ -173,23 +179,35 @@ function visitEachBlock(block) {
var bParamAdded = false;
visitSubExpression.call(this, block);

this.blocks[this.currentKey()] += "${ repeat(" + normalizePath.call(this, block.params[0].original) + ", (item: any, index: number) => item._id || index, (item: any, index: number) => ";
const reapeatDirectiveParamsTS = "(item: any, index: number) => item._id || index, (item: any, index: number)";
const reapeatDirectiveParamsJS = "(item, index) => item._id || index, (item, index)";
const repleatDirectiveParams = process.env.UI5_TS ? reapeatDirectiveParamsTS : reapeatDirectiveParamsJS;
this.blocks[this.currentKey()] += "${ repeat(" + normalizePath.call(this, block.params[0].original) + ", " + repleatDirectiveParams + " => ";
this.paths.push(normalizePath.call(this, block.params[0].original));
this.blockLevel++;

if (this.blockParametersDefinition.indexOf("item: any") === -1) {
// block params is [this, context, tags, suffix] for top level blocks
// blcok params is [this, context, tags, suffix, item, index] for nested blocks
if (!this.blockParametersUsage.includes("index")) {
// last item is not index, but an each block is processed, add the paramters for further nested blocks
bParamAdded = true;
this.blockParametersDefinition.unshift("index: number");
this.blockParametersDefinition.unshift("item: any");
this.blockParametersUsage.unshift("index");
this.blockParametersUsage.unshift("item");
if (process.env.UI5_TS) {
this.blockParametersDefinition.push("item: any");
this.blockParametersDefinition.push("index: number");
} else {
this.blockParametersDefinition.push("item");
this.blockParametersDefinition.push("index");
}
this.blockParametersUsage.push("item");
this.blockParametersUsage.push("index");
}
this.acceptKey(block, "program");
if (bParamAdded) {
this.blockParametersDefinition.shift("item: any");
this.blockParametersDefinition.shift("index: number");
this.blockParametersUsage.shift("item");
this.blockParametersUsage.shift("index");
// if parameters were added at this step, remove the last two
this.blockParametersDefinition.pop();
this.blockParametersDefinition.pop();
this.blockParametersUsage.pop();
this.blockParametersUsage.pop();
}
this.blockLevel--;
this.blocks[this.currentKey()] += ") }";
Expand Down
15 changes: 10 additions & 5 deletions packages/tools/lib/hbs2lit/src/svgProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const svgrx = new RegExp(/<svg[\s\S]*?>([\s\S]*?)<\/svg>/, 'g');
const blockrx = /block[0-9]+/g;

function process(input) {
function processSVG(input) {
let matches;
let template = input;
let blockCounter = 0;
Expand Down Expand Up @@ -45,11 +45,16 @@ function getSVGMatches(template) {
}

function getSVGBlock(input, blockCounter) {
const definitionTS = `\nfunction blockSVG${blockCounter} (this: any, context: UI5Element, tags: string[], suffix: string | undefined) {
return svg\`${input}\`;
};`;
const definitionJS = `\nfunction blockSVG${blockCounter} (context, tags, suffix) {
return svg\`${input}\`;
};`;

return {
usage: `\${blockSVG${blockCounter}.call(this, context, tags, suffix)}`,
definition: `\nfunction blockSVG${blockCounter} (this: any, context: UI5Element, tags: string[], suffix: string | undefined) {
return svg\`${input}\`;
};`,
definition: process.env.UI5_TS ? definitionTS : definitionJS,
};
}

Expand All @@ -67,5 +72,5 @@ function replaceInternalBlocks(template, svgContent) {
}

module.exports = {
process: process
process: processSVG,
};
19 changes: 14 additions & 5 deletions packages/tools/lib/hbs2ui5/RenderTemplates/LitRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,20 @@ jsControls = ["RatingIndicator",
"Wizard",
]

const tsImports = (controlName) => {
if (!process.env.UI5_TS) {
return "";
}

const importPrefix = process.env.UI5_BASE ? "../../../" : "@ui5/webcomponents-base/dist/"

return `import type UI5Element from "${importPrefix}UI5Element";
${importForControl(controlName)}
import type { ClassMapValue } from "${importPrefix}types";
`;
}
const importForControl = (controlName) => {

if (jsControls.includes(controlName)) {
return `type ${controlName} = any;`;
}
Expand All @@ -52,13 +65,9 @@ const importForControl = (controlName) => {

const buildRenderer = (controlName, litTemplate) => {
// typescript cannot process package imports for the same package and the paths are changed to relative for base package templates
const importPrefix = process.env.UI5_BASE ? "../../../" : "@ui5/webcomponents-base/dist/"
return `/* eslint no-unused-vars: 0 */
import { html, svg, repeat, classMap, styleMap, ifDefined, unsafeHTML, scopeTag } from "${importPrefix}renderer/LitRenderer.js";
import type UI5Element from "${importPrefix}UI5Element";
${importForControl(controlName)}
import type { ClassMapValue } from "${importPrefix}types";

${tsImports(controlName)}
${litTemplate}

export default block0;`;
Expand Down
3 changes: 2 additions & 1 deletion packages/tools/lib/hbs2ui5/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const isHandlebars = (fileName) => fileName.indexOf('.hbs') !== -1;
const processFile = async (file, outputDir) => {
const componentNameMatcher = /(\w+)(\.hbs)/gim;
const componentName = componentNameMatcher.exec(file)[1];
console.log({componentName})
const litCode = await hbs2lit(file, componentName);
const absoluteOutputDir = composeAbsoluteOutputDir(file, outputDir);

Expand Down Expand Up @@ -70,7 +71,7 @@ const writeRenderers = async (outputDir, controlName, fileContent) => {

await fs.mkdir(outputDir, { recursive: true });

const compiledFilePath = `${outputDir}${path.sep}${controlName}Template.lit.ts`;
const compiledFilePath = `${outputDir}${path.sep}${controlName}Template.lit.${process.env.UI5_TS ? "ts" : "js"}`;

// strip DOS line endings because the break the source maps
let fileContentUnix = fileContent.replace(/\r\n/g, "\n");
Expand Down