From eeaa2fb472404739e72c5823fd13261be0a7eda5 Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 09:32:19 -0700 Subject: [PATCH 1/6] moving to async createHandlebars function to do dynamic import --- .c8rc | 9 +++++++++ index.d.ts | 4 ---- index.js | 8 -------- index.ts | 23 +++++++++++++++++++++++ package.json | 19 +++++++++---------- test/es6.mjs | 12 ++++++++---- test/index.js | 11 +++++++---- tsconfig.json | 22 ++++++++++++++++++++++ 8 files changed, 78 insertions(+), 30 deletions(-) create mode 100644 .c8rc delete mode 100644 index.d.ts delete mode 100644 index.js create mode 100644 index.ts create mode 100644 tsconfig.json diff --git a/.c8rc b/.c8rc new file mode 100644 index 0000000..4b22f6b --- /dev/null +++ b/.c8rc @@ -0,0 +1,9 @@ +{ + "exclude": [ + "test/**", + "dist/**", + "**/*.test.js", + "**/*.spec.ts", + "node_modules/**" + ] +} \ No newline at end of file diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index 592807f..0000000 --- a/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import * as Handlebars from 'handlebars'; -import { handlebarHelpers } from './handlebarHelpers'; -export = Handlebars; -export { handlebarHelpers }; diff --git a/index.js b/index.js deleted file mode 100644 index 466ea61..0000000 --- a/index.js +++ /dev/null @@ -1,8 +0,0 @@ -const HandlebarsLib = require('handlebars'); -const helpers = require('./helpers.js'); - -const handlebars = HandlebarsLib.create(); -helpers({ handlebars: handlebars }); - -module.exports = handlebars; -module.exports.handlebarHelpers = helpers; diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..af7b708 --- /dev/null +++ b/index.ts @@ -0,0 +1,23 @@ +import * as HandlebarsLib from 'handlebars'; +import helpersLib from './helpers.js'; + +/** + * Fumanchu Handlebars instance + * @type {Handlebars} + */ +export const handlebars = HandlebarsLib.create(); +/** + * Fumanchu Handlebars helpers + */ +export const helpers = helpersLib; + +/** + * Create a new Handlebars instance with Fumanchu helpers + * @returns {Promise} + */ +export async function createHandlebars() { + const handlebars = HandlebarsLib.create(); + const helpersFunction = await import('./helpers.js'); + helpersFunction.default({ handlebars: handlebars }); + return handlebars; +} \ No newline at end of file diff --git a/package.json b/package.json index 57a3983..5c86d6a 100644 --- a/package.json +++ b/package.json @@ -88,19 +88,17 @@ }, "license": "MIT", "files": [ - "index.js", - "index.mjs", - "helpers.js", - "lib", "dist", - "index.d.ts" + "license" ], - "source": "index.js", - "main": "index.js", - "types": "index.d.ts", + "source": "dist/index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "test": "c8 mocha --reporter list", - "test:ci": "c8 --reporter=lcov mocha --reporter list", + "test": "npm run build && c8 mocha --reporter list", + "test:ci": "npm run build && c8 --reporter=lcov mocha --reporter list", + "build": "rimraf ./dist && tsc", + "prepare": "npm run build", "clean": "rimraf ./node_modules ./coverage yarn.lock package-lock.json ./dist ./dist-site", "website:build": "rimraf ./site/readme.md && npx -y docula build -s ./site -o ./dist-site", "website:serve": "rimraf ./site/readme.md && npx -y docula serve -s ./site -o ./dist-site" @@ -146,6 +144,7 @@ "rimraf": "^6.0.1", "template-helpers": "^1.0.1", "templates": "^1.2.9", + "typecript": "^0.0.1-security", "typescript": "^5.6.3" } } diff --git a/test/es6.mjs b/test/es6.mjs index d53443e..181a863 100644 --- a/test/es6.mjs +++ b/test/es6.mjs @@ -1,8 +1,10 @@ -import handlebars from '../index.js'; +import {createHandlebars, helpers, handlebars} from '../dist/index.js'; import {expect} from 'chai'; describe('testing es6 examples', function() { - it('should get the handlebars from an es6 import', function() { + it('should get the handlebars from an es6 import', async function() { + const handlebars = await createHandlebars(); + // Use Fumanchu instead of Handlebars const source = 'Hello, {{name}}!'; const template = handlebars.compile(source); @@ -13,7 +15,9 @@ describe('testing es6 examples', function() { expect(result).to.equal('Hello, John!'); //testing the export of handlebarHelpers - const {handlebarHelpers} = handlebars; - expect(handlebarHelpers).to.be.a('function'); + expect(helpers).to.be.a('function'); + + //testing the export of handlebarHelpers + expect(handlebars).to.not.be.undefined; }); }); \ No newline at end of file diff --git a/test/index.js b/test/index.js index 271e443..6b9f66d 100644 --- a/test/index.js +++ b/test/index.js @@ -1,10 +1,12 @@ var assert = require('assert'); const chai = require('chai'); const expect = chai.expect; -const Fumanchu = require('../index.js'); +const {createHandlebars} = require('../dist/index.js'); describe('Fumanchu Template Test', function() { - it('should render name correctly', function() { + it('should render name correctly', async function() { + const Fumanchu = await createHandlebars(); + // Use Fumanchu instead of Handlebars const source = 'Hello, {{name}}!'; const template = Fumanchu.compile(source); @@ -15,13 +17,14 @@ describe('Fumanchu Template Test', function() { expect(result).to.equal('Hello, John!'); }); - it('should return the sum of two numbers.', function() { + it('should return the sum of two numbers.', async function() { + const Fumanchu = await createHandlebars(); var fn = Fumanchu.compile('{{add value 5}}'); assert.equal(fn({value: 5}), '10'); }); it('should have the helper class exported', function() { - var helpers = require('../index.js').handlebarHelpers; + var helpers = require('../dist/index.js').helpers; const HandlebarsLib = require('handlebars'); const handlebars = HandlebarsLib.create(); helpers({ handlebars: handlebars }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8ab8aed --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES6", // or your preferred target version + "module": "commonjs", // or your preferred module type + "allowJs": true, // Enable JavaScript files in the project + "checkJs": false, // Set to true if you want type-checking for JS files + "outDir": "./dist", // Specify output directory + "strict": true, // Enable strict type checking options + "esModuleInterop": true, // Required if you are using ES modules + "skipLibCheck": true, // Skipping type checks on declaration files + "declaration": true // Generate corresponding .d.ts file + }, + "include": [ + "helpers.js", + "src/**/*.js", + "index.ts" + ], + "exclude": [ + "node_modules", + "test/**/*.js", // Exclude test files or other JS files you don't want to compile + ] +} \ No newline at end of file From 873821fcf4b895cf49111f32f6e902b65ce2191c Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 09:57:57 -0700 Subject: [PATCH 2/6] adding in Handlebars library without instance --- index.ts | 8 +++++++- test/es6.mjs | 11 +++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/index.ts b/index.ts index af7b708..3214376 100644 --- a/index.ts +++ b/index.ts @@ -2,7 +2,13 @@ import * as HandlebarsLib from 'handlebars'; import helpersLib from './helpers.js'; /** - * Fumanchu Handlebars instance + * Handlebars library not initiated with helpers + * @type {Handlebars} + */ +export const Handlebars = HandlebarsLib; + +/** + * Fumanchu Handlebars instance not initiated with helpers * @type {Handlebars} */ export const handlebars = HandlebarsLib.create(); diff --git a/test/es6.mjs b/test/es6.mjs index 181a863..fad525f 100644 --- a/test/es6.mjs +++ b/test/es6.mjs @@ -1,13 +1,13 @@ -import {createHandlebars, helpers, handlebars} from '../dist/index.js'; +import {createHandlebars, helpers, handlebars, Handlebars} from '../dist/index.js'; import {expect} from 'chai'; describe('testing es6 examples', function() { it('should get the handlebars from an es6 import', async function() { - const handlebars = await createHandlebars(); + const fumanchu = await createHandlebars(); // Use Fumanchu instead of Handlebars const source = 'Hello, {{name}}!'; - const template = handlebars.compile(source); + const template = fumanchu.compile(source); // Render the template with a context const result = template({ name: 'John' }); @@ -18,6 +18,9 @@ describe('testing es6 examples', function() { expect(helpers).to.be.a('function'); //testing the export of handlebarHelpers - expect(handlebars).to.not.be.undefined; + expect(handlebars.compile).to.not.be.undefined; + + //test the Handlebars object + expect(Handlebars.create).to.not.be.undefined; }); }); \ No newline at end of file From 9ae2325767b4f16c095b9d141794091ca342f7da Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 10:04:41 -0700 Subject: [PATCH 3/6] adding in tsup --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5c86d6a..255a71a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@jaredwray/fumanchu", "description": "Handlebars + Helpers = Fumanchu", - "version": "2.1.0", + "version": "3.0.0", "homepage": "https://github.com/jaredwray/fumanchu", "author": "Jared Wray (me@jaredwray.com)", "keywords": [ @@ -97,7 +97,7 @@ "scripts": { "test": "npm run build && c8 mocha --reporter list", "test:ci": "npm run build && c8 --reporter=lcov mocha --reporter list", - "build": "rimraf ./dist && tsc", + "build": "rimraf ./dist && tsup ./index.ts --format cjs --dts --clean", "prepare": "npm run build", "clean": "rimraf ./node_modules ./coverage yarn.lock package-lock.json ./dist ./dist-site", "website:build": "rimraf ./site/readme.md && npx -y docula build -s ./site -o ./dist-site", @@ -139,11 +139,13 @@ "devDependencies": { "c8": "^10.1.2", "chai": "^4.3.10", + "docula": "^0.9.4", "lodash": "^4.17.21", "mocha": "^10.7.3", "rimraf": "^6.0.1", "template-helpers": "^1.0.1", "templates": "^1.2.9", + "tsup": "^8.3.5", "typecript": "^0.0.1-security", "typescript": "^5.6.3" } From 0d131cc879b5f1b45871cf066c44175b9c4b3911 Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 10:31:10 -0700 Subject: [PATCH 4/6] Update README.md --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3ffcce1..a216cd4 100644 --- a/README.md +++ b/README.md @@ -12,63 +12,95 @@ Handlebars + Helpers Together [Handlebars](https://github.com/handlebars-lang/handlebars.js) + [Handlebars-helpers](https://github.com/helpers/handlebars-helpers) (helpers are now maintained in this project) combined into a single package. Easily use in your nodejs as it is a drop in replacement when using handlebars directly. -## Table of Contents +We plan to make significant changes over time with this project such as the following: +- **(Completed)** Remove all dependencies on `handlebars-helpers` and maintain all helpers in this project +- **(In Progress)** Migrate to Typescript with full typing support +- **(In Progress)** Replace module dependencies that are no longer supported with supported ones +- Migration to ESM and CJS support using cross compatible code +- Migration to `vitest` as a testing framework +- Migration to `xo` as a linting framework +- Move to better documentation and examples where it makes sense +- Add in browser support via CDN (this will remove the nodejs specific helpers) + +# Breaking Changes from v2 to v3 + +Because of the complexity in the legacy helpers library we have moved to exporting the libraries and a helper function to make it easier to use. Here are the exports: + +- `handlebars` - This is an instance of handlebars library without any helpers. It is the same as calling `Handlebars.create()` +- `helpers` - This is a function that takes an object with a `handlebars` key and adds all the helpers to the handlebars instance. This is the same as calling `helpers({ handlebars: handlebars })` +- `createHandlebars` - This is an async function that returns a handlebars instance with all the helpers added. This is the same as calling `helpers({ handlebars: handlebars })` but async. +- `Handlebars` - This is the handlebars library itself. It is the same as calling `require('handlebars')` + +Please see the examples below for how to use the library. + +# Table of Contents * [Using in Nodejs](#using-in-nodejs) * [Just using Handlebar Helpers](#using-handlebars-helpers) * [Helpers](#helpers) * [How to Contribute](#how-to-contribute) * [License and Copyright](#license-and-copyright) -## Usage Nodejs + +# Usage Nodejs ```bash npm install @jaredwray/fumanchu --save ``` ```javascript -var handlebars = require('@jaredwray/fumanchu'); +var {handlebars, helpers} = require('@jaredwray/fumanchu'); +helpers({ handlebars: handlebars }); var template = handlebars.compile('{{#if (eq foo "bar")}}

Foo is bar

{{/if}}'); var html = template({foo: 'bar'}); console.log(html); ``` -If using it with es6 you can access `handlebars` via destructuring: +If using it with es6 you can access `handlebars` and `helpers`: ```javascript -import handlebars from '@jaredwray/fumanchu'; +import {handlebars, helpers} from '@jaredwray/fumanchu'; +helpers({ handlebars: handlebars }); const template = handlebars.compile('{{#if (eq foo "bar")}}

Foo is bar

{{/if}}'); const html = template({foo: 'bar'}); console.log(html); ``` +If you want to just get an instance of handlebars via `createHandlebars` you can do the following **(it is async)**: + +```javascript +import {createHandlebars} from '@jaredwray/fumanchu'; +const handlebars = await createHandlebars(); //this will return a handlebars instance with all helpers +const template = handlebars.compile('{{#if (eq foo "bar")}}

Foo is bar

{{/if}}'); +const html = template({foo: 'bar'}); +console.log(html); //

Foo is bar

+``` + It's just that easy! No need to add Handlebars to your project, it's already included. -## Using Handlebars Helpers +# Using Handlebars Helpers If you only want to use handlebar helpers you can easily do that by doing the following: ```javascript -var helpers = require('@jaredwray/fumanchu').handlebarHelpers; +var {helpers} = require('@jaredwray/fumanchu'); var handlebars = require('handlebars'); helpers({ handlebars: handlebars }); var fn = handlebars.compile('{{add value 5}}'); -console.log(fn); +console.log(fn); // 10 ``` If using it with es6 you can access `helpers` via destructuring: ```javascript -import fumanchu, {handlebarHelpers} from '@jaredwray/fumanchu'; +import {helpers} from '@jaredwray/fumanchu'; import handlebars from 'handlebars'; -handlebarHelpers({ handlebars: handlebars }); +helpers({ handlebars: handlebars }); const template = handlebars.compile('{{#if (eq foo "bar")}}

Foo is bar

{{/if}}'); const html = template({foo: 'bar'}); -console.log(html); +console.log(html); //

Foo is bar

``` -Notice that in this scenario you are accessing helpers via `helpers` from `fumanchu` instead of just using handlebars via fumanchu directly. - -## Helpers +# Helpers More than 180 Handlebars helpers in ~20 categories. Helpers can be used with Assemble, Generate, Verb, Ghost, gulp-handlebars, grunt-handlebars, consolidate, or any node.js/Handlebars project. ## Categories @@ -96,7 +128,7 @@ Currently **189 helpers** in **20 categories**: * **[string](#string)** ([code](lib/string.js) | [unit tests](test/string.js)) * **[url](#url)** ([code](lib/url.js) | [unit tests](test/url.js)) -## All helpers +# All helpers ### [array helpers](#array) From 99719238f84ebfd118c4fdc04b77d9cd0469333a Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 10:31:17 -0700 Subject: [PATCH 5/6] fixing site --- site/{docula.config.cjs => docula.config.mjs} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename site/{docula.config.cjs => docula.config.mjs} (75%) diff --git a/site/docula.config.cjs b/site/docula.config.mjs similarity index 75% rename from site/docula.config.cjs rename to site/docula.config.mjs index d1cf7ff..e298487 100644 --- a/site/docula.config.cjs +++ b/site/docula.config.mjs @@ -1,15 +1,15 @@ -const path = require('node:path'); -const process = require('node:process'); -const fs = require('node:fs'); +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; -module.exports.options = { +export const options = { githubPath: 'jaredwray/fumanchu', siteTitle: 'Fumanchu', siteDescription: 'Handlebars + Helpers Together', siteUrl: 'https://fumanchu.org', }; -module.exports.onPrepare = async config => { +export const onPrepare = async config => { const readmePath = path.join(process.cwd(), './README.md'); const readmeSitePath = path.join(config.sitePath, 'README.md'); const readme = await fs.promises.readFile(readmePath, 'utf8'); From a3e11ee66bb89286168e2a86f70e9a9e1147fac6 Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Mon, 28 Oct 2024 10:31:24 -0700 Subject: [PATCH 6/6] adding in tests --- test/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/index.js b/test/index.js index 6b9f66d..12cb3cc 100644 --- a/test/index.js +++ b/test/index.js @@ -31,5 +31,12 @@ describe('Fumanchu Template Test', function() { var fn = handlebars.compile('{{add value 5}}'); assert.equal(fn({value: 5}), '10'); }); + + it('should have the handlebars object exported', function() { + var {handlebars, helpers} = require('../dist/index.js'); + helpers({ handlebars: handlebars }); + var fn = handlebars.compile('{{add value 5}}'); + assert.equal(fn({value: 5}), '10'); + }); });