Skip to content

Commit

Permalink
Adds helper
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfarrell76 committed Oct 17, 2023
1 parent 3f2d3bc commit e708553
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"devDependencies": {
"@types/chai": "^4.3.4",
"@types/lodash": "^4.14.199",
"@types/mocha": "^10.0.1",
"@types/mocha": "^10.0.2",
"@types/pluralize": "^0.0.31",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.12.1",
Expand Down
116 changes: 116 additions & 0 deletions src/getVariablesFromHandlebarsTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import handlebars from 'handlebars';

/**
* Parse AST for variables
*
* @param statement - Statement to parse
* @returns Variables
*/
function parseHandlebarsAst(statement: hbs.AST.Statement): {
[k in string]: unknown;
} {
// No variables
if (statement.type === 'ContentStatement') {
return {};
}

if (statement.type === 'PartialStatement') {
const moustacheStatement = statement as hbs.AST.PartialStatement;
const pathStatement = moustacheStatement.name as hbs.AST.PathExpression;
return {
[pathStatement.original]: 'partial',
};
}

// Parse variables from {{ var }}
if (statement.type === 'MustacheStatement') {
const moustacheStatement = statement as hbs.AST.MustacheStatement;
const paramsExpressionList =
moustacheStatement.params as hbs.AST.PathExpression[];
const pathExpression = moustacheStatement.path as hbs.AST.PathExpression;
const vars = [
...paramsExpressionList.map(({ original }) => original),
pathExpression.original,
].filter((x) => !!x);
return vars.reduce((acc, x) => Object.assign(acc, { [x]: null }), {});
}

// Parse from {{#each}} or {{#with}}
if (statement.type === 'BlockStatement' && statement) {
const moustacheStatement = statement as hbs.AST.MustacheStatement;
const paramsExpressionList =
moustacheStatement.params as hbs.AST.PathExpression[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const program = (moustacheStatement as any).program as hbs.AST.Program;
const param = paramsExpressionList[0] as unknown as
| hbs.AST.PathExpression
| hbs.AST.SubExpression;
const pathExpression = moustacheStatement.path as hbs.AST.PathExpression;
if (param.type === 'SubExpression') {
return program.body
.map(parseHandlebarsAst)
.reduce((acc, obj) => Object.assign(acc, obj), {});
}

if (pathExpression.original === 'each') {
return {
[param.original]: [
program.body
.map(parseHandlebarsAst)
.reduce((acc, obj) => Object.assign(acc, obj), {}),
],
};
}

return {
[param.original]: program.body
.map(parseHandlebarsAst)
.reduce((acc, obj) => Object.assign(acc, obj), {}),
};
}
throw new Error(`Unknown statement: ${statement.type}`);
}

/**
* Get variables from handlebars template
*
* @param template - Template
* @returns Variables
*/
export function getVariablesFromHandlebarsTemplate(template: string): {
[k in string]: unknown;
} {
const ast = handlebars.parseWithoutProcessing(template);

const results = ast.body.map(parseHandlebarsAst);
return results.reduce((acc, data) => {
Object.entries(data).forEach(([k, v]) => {
const existing = acc[k];
if (!existing) {
return Object.assign(acc, { [k]: v });
}
if (Array.isArray(existing) && Array.isArray(v)) {
return Object.assign(acc, {
[k]: [
{
...existing[0],
...v[0],
},
],
});
}
if (typeof existing === 'object' && typeof v === 'object') {
return Object.assign(acc, {
[k]: {
...existing,
...v,
},
});
}
return Object.assign(acc, {
[k]: v,
});
});
return acc;
}, {});
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './change-case';
export * from './createHandlebars';
export * from './getVariablesFromHandlebarsTemplate';
61 changes: 61 additions & 0 deletions src/tests/getVariablesFromHandlebarsTemplate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { expect } from 'chai';

import { getVariablesFromHandlebarsTemplate } from '../index';

const TEST_HBS = `
<p>
You are an experienced project manager, constantly juggling a variety of different tasks.
Other employees at your company are very busy.
They quickly record notes in slack of things that they want to look into later.
You are tasked with reviewing those raw notes, and turning them into a structured
form that will make the notes more easily indexable by the employee when they have more time to review the information.
{{{ description }}}. Return a JSON object in the following format:
({{#each parameters}}{{ name }} - {{slug}}, {{/each}}clarification).
</p>
{{> promptPartialTodaysDate }}
{{> promptPartialTranscendProducts }}
{{#with dog}}{{cat}} - {{fish}}{{/with}}
{{#if (listLen extraContext)}}
{{#each extraContext}}
{{ name }}
{{/each}}
{{/if}}
<p>
The following rules define each of the input parameters:
<ul>
{{#each parameters}}
<li>{{ name }}: {{{ description }}}</li>
{{/each}}
</ul>
</p>
{{#with dog}} {{meow}}{{/with}}
<p>
If any of the parameters are not known, it should be set to null.
If anything is not clear, return a prompt in the clarification key of the response asking for further detail
</p>`;

describe('getVariablesFromHandlebars', () => {
it('should merge together', () => {
expect(getVariablesFromHandlebarsTemplate(TEST_HBS)).to.deep.equal({
description: null,
parameters: [{ name: null, slug: null, description: null }],
dog: { cat: null, fish: null, meow: null },
extraContext: [
{
name: null,
},
],
promptPartialTodaysDate: 'partial',
promptPartialTranscendProducts: 'partial',
});
});
});
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ __metadata:
"@transcend-io/type-utils": ^1.1.1
"@types/chai": ^4.3.4
"@types/lodash": ^4.14.199
"@types/mocha": ^10.0.1
"@types/mocha": ^10.0.2
"@types/pluralize": ^0.0.31
"@typescript-eslint/eslint-plugin": ^5.12.1
"@typescript-eslint/parser": ^5.12.1
Expand Down Expand Up @@ -441,7 +441,7 @@ __metadata:
languageName: node
linkType: hard

"@types/mocha@npm:^10.0.1":
"@types/mocha@npm:^10.0.2":
version: 10.0.2
resolution: "@types/mocha@npm:10.0.2"
checksum: a78a02691f102beb02f9ec435458107d21b518fc477c3b2f37c90b8e70b67bff888351715ae173bd31ede25ee5e0d688aefb0faf4284034d08ba63027c8b0c01
Expand Down

0 comments on commit e708553

Please sign in to comment.