From 3fb668701363fe85eef7dd8b8fc3e451ae8bd0b9 Mon Sep 17 00:00:00 2001 From: Timothy Lindvall Date: Tue, 19 Mar 2019 16:07:05 -0700 Subject: [PATCH] Port over linting and test for typings - Move typings from lib/ to types/. - Add dtslint for validating types. - Use grunt-bg-shell to call out to dtslint during build step. --- Gruntfile.js | 10 +++ package.json | 8 ++- lib/handlebars.d.ts => types/index.d.ts | 3 +- types/test.ts | 91 +++++++++++++++++++++++++ types/tsconfig.json | 16 +++++ types/tslint.json | 79 +++++++++++++++++++++ 6 files changed, 204 insertions(+), 3 deletions(-) rename lib/handlebars.d.ts => types/index.d.ts (98%) create mode 100644 types/test.ts create mode 100644 types/tsconfig.json create mode 100644 types/tslint.json diff --git a/Gruntfile.js b/Gruntfile.js index 838e7b395..738a8c792 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -187,6 +187,14 @@ module.exports = function(grunt) { } }, + bgShell: { + checkTypes: { + cmd: 'npm run checkTypes', + bg: false, + fail: true + } + }, + watch: { scripts: { options: { @@ -202,6 +210,7 @@ module.exports = function(grunt) { // Build a new version of the library this.registerTask('build', 'Builds a distributable version of the current project', [ 'eslint', + 'bgShell:checkTypes', 'parser', 'node', 'globals']); @@ -222,6 +231,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-babel'); + grunt.loadNpmTasks('grunt-bg-shell'); grunt.loadNpmTasks('grunt-eslint'); grunt.loadNpmTasks('grunt-saucelabs'); grunt.loadNpmTasks('grunt-webpack'); diff --git a/package.json b/package.json index edf11b7c2..de504a42a 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,12 @@ "babel-loader": "^5.0.0", "babel-runtime": "^5.1.10", "benchmark": "~1.0", + "dtslint": "^0.5.5", "dustjs-linkedin": "^2.0.2", "eco": "~1.1.0-rc-3", "grunt": "^1.0.3", "grunt-babel": "^5.0.0", + "grunt-bg-shell": "^2.3.3", "grunt-cli": "^1", "grunt-contrib-clean": "^1", "grunt-contrib-concat": "^1", @@ -59,11 +61,12 @@ "webpack-dev-server": "^1.12.1" }, "main": "lib/index.js", - "types": "lib/handlebars.d.ts", + "types": "types/index.d.ts", "bin": { "handlebars": "bin/handlebars" }, "scripts": { + "checkTypes": "dtslint types", "test": "grunt" }, "jspm": { @@ -83,6 +86,7 @@ "lib", "print-script", "release-notes.md", - "runtime.js" + "runtime.js", + "types/*.d.ts" ] } diff --git a/lib/handlebars.d.ts b/types/index.d.ts similarity index 98% rename from lib/handlebars.d.ts rename to types/index.d.ts index 181ef2ff5..237bfa580 100644 --- a/lib/handlebars.d.ts +++ b/types/index.d.ts @@ -8,8 +8,9 @@ * - Sergei Dorogin * - webbiesdk * For full history prior to their migration to handlebars.js, please see: - * https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/handlebars + * https://github.com/DefinitelyTyped/DefinitelyTyped/commits/1ce60bdc07f10e0b076778c6c953271c072bc894/types/handlebars/index.d.ts */ +// TypeScript Version: 2.3 declare namespace Handlebars { export interface TemplateDelegate { diff --git a/types/test.ts b/types/test.ts new file mode 100644 index 000000000..fd0b7bb1b --- /dev/null +++ b/types/test.ts @@ -0,0 +1,91 @@ +/* These test cases were imported from https://github.com/DefinitelyTyped/DefinitelyTyped + * and includes previous contributions from the DefinitelyTyped community. + * For full history prior to their migration to handlebars.js, please see: + * https://github.com/DefinitelyTyped/DefinitelyTyped/commits/1ce60bdc07f10e0b076778c6c953271c072bc894/types/handlebars/handlebars-tests.ts + */ + +import * as Handlebars from 'handlebars'; + +const context = { + author: { firstName: 'Alan', lastName: 'Johnson' }, + body: 'I Love Handlebars', + comments: [{ + author: { firstName: 'Yehuda', lastName: 'Katz' }, + body: 'Me too!' + }] +}; +Handlebars.registerHelper('fullName', (person: typeof context.author) => { + return person.firstName + ' ' + person.lastName; +}); + +Handlebars.registerHelper('agree_button', function(this: any) { + return new Handlebars.SafeString( + '' + ); +}); + +const source1 = '

Hello, my name is {{name}}. I am from {{hometown}}. I have ' + + '{{kids.length}} kids:

' + + '
    {{#kids}}
  • {{name}} is {{age}}
  • {{/kids}}
'; +const template1 = Handlebars.compile(source1); +template1({ name: "Alan", hometown: "Somewhere, TX", kids: [{name: "Jimmy", age: 12}, {name: "Sally", age: 4}]}); + +Handlebars.registerHelper('link_to', (context: typeof post) => { + return '' + context.body + ''; +}); +const post = { url: "/hello-world", body: "Hello World!" }; +const context2 = { posts: [post] }; +const source2 = '
    {{#posts}}
  • {{{link_to this}}}
  • {{/posts}}
'; +const template2: HandlebarsTemplateDelegate<{ posts: { url: string, body: string }[] }> = Handlebars.compile(source2); +template2(context2); + +Handlebars.registerHelper('link_to', (title: string, context: typeof post) => { + return '' + title + '!'; +}); +const context3 = { posts: [{url: '/hello-world', body: 'Hello World!'}] }; +const source3 = '
    {{#posts}}
  • {{{link_to "Post" this}}}
  • {{/posts}}
'; +const template3 = Handlebars.compile(source3); +template3(context3); + +const source4 = '
    {{#people}}
  • {{#link}}{{name}}{{/link}}
  • {{/people}}
'; +Handlebars.registerHelper('link', function(this: any, context: any) { + return '' + context.fn(this) + ''; +}); +const template4 = Handlebars.compile<{ people: { name: string, id: number }[] }>(source4); +const data2 = { 'people': [ + { 'name': 'Alan', 'id': 1 }, + { 'name': 'Yehuda', 'id': 2 } +]}; +template4(data2); + +const source5 = '
    {{#people}}
  • {{> link}}
  • {{/people}}
'; +Handlebars.registerPartial('link', '{{name}}'); +const template5 = Handlebars.compile(source5); +const data3 = { 'people': [ + { 'name': 'Alan', 'id': 1 }, + { 'name': 'Yehuda', 'id': 2 } +]}; +template5(data3); + +const source6 = '{{#list nav}}{{title}}{{/list}}'; +const template6 = Handlebars.compile(source6); +Handlebars.registerHelper('list', (context, options: Handlebars.HelperOptions) => { + let ret = "
    "; + for(let i=0, j=context.length; i" + options.fn(context[i]) + ""; + } + return ret + "
"; +}); +template6([{url:"", title:""}]) + + +const escapedExpression = Handlebars.Utils.escapeExpression(''); + +Handlebars.helpers !== undefined; + +const parsedTmpl = Handlebars.parse('

Hello, my name is {{name}}.

', { + srcName: "/foo/bar/baz.hbs", + ignoreStandalone: true +}); + +const parsedTmplWithoutOptions = Handlebars.parse('

Hello, my name is {{name}}.

'); \ No newline at end of file diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 000000000..86328ebb1 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es6"], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noEmit": true, + + "baseUrl": ".", + "paths": { + "handlebars": ["."] + } + } +} \ No newline at end of file diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 000000000..a484bf6b0 --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,79 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "adjacent-overload-signatures": false, + "array-type": false, + "arrow-return-shorthand": false, + "ban-types": false, + "callable-types": false, + "comment-format": false, + "dt-header": false, + "eofline": false, + "export-just-namespace": false, + "import-spacing": false, + "interface-name": false, + "interface-over-type-literal": false, + "jsdoc-format": false, + "max-line-length": false, + "member-access": false, + "new-parens": false, + "no-any-union": false, + "no-boolean-literal-compare": false, + "no-conditional-assignment": false, + "no-consecutive-blank-lines": false, + "no-construct": false, + "no-declare-current-package": false, + "no-duplicate-imports": false, + "no-duplicate-variable": false, + "no-empty-interface": false, + "no-for-in-array": false, + "no-inferrable-types": false, + "no-internal-module": false, + "no-irregular-whitespace": false, + "no-mergeable-namespace": false, + "no-misused-new": false, + "no-namespace": false, + "no-object-literal-type-assertion": false, + "no-padding": false, + "no-redundant-jsdoc": false, + "no-redundant-jsdoc-2": false, + "no-redundant-undefined": false, + "no-reference-import": false, + "no-relative-import-in-test": false, + "no-self-import": false, + "no-single-declare-module": false, + "no-string-throw": false, + "no-unnecessary-callback-wrapper": false, + "no-unnecessary-class": false, + "no-unnecessary-generics": false, + "no-unnecessary-qualifier": false, + "no-unnecessary-type-assertion": false, + "no-useless-files": false, + "no-var-keyword": false, + "no-var-requires": false, + "no-void-expression": false, + "no-trailing-whitespace": false, + "object-literal-key-quotes": false, + "object-literal-shorthand": false, + "one-line": false, + "one-variable-per-declaration": false, + "only-arrow-functions": false, + "prefer-conditional-expression": false, + "prefer-const": false, + "prefer-declare-function": false, + "prefer-for-of": false, + "prefer-method-signature": false, + "prefer-template": false, + "radix": false, + "semicolon": false, + "space-before-function-paren": false, + "space-within-parens": false, + "strict-export-declare-modifiers": false, + "trim-file": false, + "triple-equals": false, + "typedef-whitespace": false, + "unified-signatures": false, + "void-return": false, + "whitespace": false + } +} \ No newline at end of file