-
Notifications
You must be signed in to change notification settings - Fork 1
Proposal: Lint Vue templates and check bindings against Haxe codebase
So how to validate that all stringed bindings on your Vue string-based template is strictly-typed linked to the relevant fields in your HaxeVx component class? (whether it may be Vue component properties or CSS module class bindings?).
A compile-time checking macro to compile Vue's HTML string templates' and analyse attributes for v-for
, v-on
, :attr
, {{expr}}
and various other scopes, and generate scoped/nested dummy anonymous functions of Expr
from them for typechecking purposes only during dev builds within the HaxeVX's component's Template()
call. This is an alternative approach for writing template markup that involves full compile-time type-checking (a great to run basic checks for typos and prop type mismatches, etc.), instead of relying on JSX (which is now on the HaxeVx roadmap only and not implemented yet).
This would allow both developers/designers to design directly from plain external .html files with the Vue templating language itself, but still get strict-typed compiling support with it.
If a binding is spelled wrongly, the compiler outputs out an error immediately of it, with the Position
of each generated dummy test Expr being tied to respective range of characters in the .html
file instead. With it, you can jump straight to the problematic error (depending on your IDE), with the exact location of the error marked on the html file itself.
https://vuejs.org/v2/guide/syntax.html
-
v-for="variableName in Expr"
v-for="(variableNames max 3 declarations) in Expr".
and generate respective inner scopes for anything else within that node's descendants with those variable names. -
v-on:XXX="Expr"
and@XXX="Expr"
. Includevar _event:js.html.Event
variable for VueJS's$event
. -
v-html="String Expr"
. ReturnString
. -
v-if="Expr"
v-show="Expr"
. ReturnDynamic
(to be type-coerced to Boolean in typical JS fashion) or ReturnBool
in extra-strict mode. -
<input v-model="Expr">
<input :value="Expr">
. ReturnString
for general case. But take into account specific cases in Vue where particular data types are expected (eg. For input fields,v-model.number
must returnFloat
) https://vuejs.org/v2/guide/forms.html -
:attr="Expr"
. For general case, returnDynamic
. But, ifattr
matches a Component Prop(P
) field, return type signature (if any) of Prop field instead. -
v-XXX="Expr"
. ReturnDynamic
. -
{{Expr}}
ReturnDynamic
. ~~~ReturnString
withreturn Std.string(Expr)
. (not much point i think)~~~ -
${String intepolated Expr}
. ReturnString
literal containing this string interpolated expression.
Also, how to check if the string template is well-formed HTML to begin with? Replace string interpolated tags/content ${}
with empty/dummy/div strings prior to validation against some form of generic html template syntax checker. Prefably, it should produce a traversible structure as well so you can similar iterate through the nodes and scan for the relevant attributes or text content bindings {{}}
within the dom tree, and form the relvantly scoped anonymous function(){}
expressions based on those strings.
Possible could use: https://lib.haxe.org/p/HtmlParser/
- All direct
Expr
in string template withCIdent
found, must be wrapped with a "this." reference, if no "this." reference is already found. This is to maintained consistency with resolving VueJS stringed identity values with the HaxeVx component instance itself, minimizing false positives. However, the caveat with this approach is that you can no longer use common JS library methods likeMath.
within string templates itself (unlike vanilla VueJS). For HaxeVx, you are forced to encapsulate such operations containing such JS library references (eg.Math
) and such....as actual component-specific methods.
-
filter:
support. Needs to be done on HaxeVx roadmap first. (for now, just truncate it off for Expr) - For every
"Expr"
within attribute literals, check for whole-word filter|
bar, and type-check accordingly to see if such filters are available in actual Component class.
- Vue API-related
$stuff
to their_vxStuff
equilevents if possible, otherwise replace with$stuff
with$$stuff
for output and type check this withvar _stuff
replacement. Also check validity ofstuff
within attribute context by checking against Vue API if such a binding exists. If such a binding doesn't exist, may assume it to be just a plain custom plugin-based variable on your part, but this is based on your compiler settings if "leniency" or more "dynamism" is required.
-
${}
. The look of it within HTML tags as well.
-
.vue
file format support. Read<template>
and<style>
tags accordingly to retrieve the inner string contents. Use this spec: https://github.com/Glidias/haxevx/wiki/Proposal:-Integrated-html-vue-type-file - Support for parsing different template languages under
.vue
's<template>
to HTML markup as well, via the external npm/gulp ecosystem of utilities you can run with your Haxe macro.
- Explicit Prop Prefix type checking. Not part of Vue by default, but attributes may be prefixed with a certain special symbol to explicitly indicate a Props attribute and not a plain HTML attribute, and this will run further typecheckings against Component class to see if such a prop field exist. The final output string template will have the prefixes removed.
- It's nowadays a fairly common practice in Vue to precompile string templates into actual Render() functions (if not using virtual dom/JSX) for single-page apps. For static string-only templates, may integrate HaxeVx's proposed type-checking process of string templates with Vue template compiler. https://www.npmjs.com/package/vue-template-compiler So, after HaxeVx type-checks that the given string template code compiles fine, the macro can optionally run some gulp/npm related process to execute the template compiler with the given string template markup, and create a new JS file with the actual JS render() function code. Then, simply assign by macro
this.render= __js__(render function code from JS file)
accordingly for the component's_Init()
method in Haxe, and you've got a pre-rendered string template in Haxe with type-checking done by both Haxe and string-template compiling by VueJS template compiler. - Caveat: You cannot use the typical Haxe-based dynamic string concatenation
${STYLE.cssModuleClass}
if compiling with Vue template compiler. So, for CSS modules, you are forced to used Vue's prescribed method of defining CSS module-based classes as:class
binding attributes with local computed style property. For example:<p :class="[STYLE.red, STYLE.bold]">
.
and a STYLE
computed:
inline getter must be generated as well by HaxeVx to support this,
- For strictly-typed component name references, string literals of those component names must be used instead of string-concatenated
${}
CIdent
references, or the Haxe macro would need to find a consistent way to find and replace those tokens with the actual matching component string literal names, for it to be Vue template-compiler compatible. For HaxeVx's interpretation of the.vue
file format spec (https://github.com/Glidias/haxevx/wiki/Proposal:-Integrated-html-vue-type-file), this can be easily inferred, but not if your html templates contain other extra${}
bindings outside of this spec, tied to.hx
file which can only be resolved at inline-compiling-time/runtime. (Infering the inline value of aCIdent
expression by compile macro isn't trivial to do in Haxe.)