From 33a6aaff984277d85e656280df900539b036246e Mon Sep 17 00:00:00 2001 From: Patrick Steele-Idem Date: Thu, 5 May 2016 22:39:30 -0700 Subject: [PATCH] Fixes #288 - Provide API for discovering custom tags and attributes for autocomplete/tooling purposes --- compiler/index.js | 6 +++ compiler/taglib-lookup/TaglibLookup.js | 48 ++++++++++++++++- docs/compiler-api.md | 54 +++++++++++++++++++ .../taglib-lookup/cache-lookup/test.js | 3 +- .../taglib-lookup/core-attributes/test.js | 3 +- test/autotests/taglib-lookup/core-tag/test.js | 3 +- .../taglib-lookup/custom-tag/test.js | 3 +- test/autotests/taglib-lookup/de-dupe/test.js | 3 +- .../declared-and-dynamic-attrs/test.js | 3 +- .../forEachAttribute/expected.json | 10 ++++ .../taglib-lookup/forEachAttribute/marko.json | 12 +++++ .../taglib-lookup/forEachAttribute/test.js | 12 +++++ .../taglib-lookup/forEachTag/expected.json | 33 ++++++++++++ .../taglib-lookup/forEachTag/marko.json | 11 ++++ .../taglib-lookup/forEachTag/test.js | 11 ++++ .../taglib-lookup/global-attrs/test.js | 3 +- .../taglib-lookup/nested-tags-attrs/test.js | 3 +- .../taglib-lookup/nested-tags/test.js | 3 +- .../transformers-core-only/test.js | 5 +- .../transformers-custom-node/test.js | 3 +- .../taglib-lookup/transformers/test.js | 3 +- test/taglib-lookup-test.js | 4 +- 22 files changed, 222 insertions(+), 17 deletions(-) create mode 100644 test/autotests/taglib-lookup/forEachAttribute/expected.json create mode 100644 test/autotests/taglib-lookup/forEachAttribute/marko.json create mode 100644 test/autotests/taglib-lookup/forEachAttribute/test.js create mode 100644 test/autotests/taglib-lookup/forEachTag/expected.json create mode 100644 test/autotests/taglib-lookup/forEachTag/marko.json create mode 100644 test/autotests/taglib-lookup/forEachTag/test.js diff --git a/compiler/index.js b/compiler/index.js index 7127e02bb..39b95da06 100644 --- a/compiler/index.js +++ b/compiler/index.js @@ -175,6 +175,12 @@ exports.taglibLookup = taglibLookup; exports.taglibLoader = require('./taglib-loader'); exports.taglibFinder = require('./taglib-finder'); +function buildTaglibLookup(dirname) { + return taglibLookup.buildLookup(dirname); +} + +exports.buildTaglibLookup = buildTaglibLookup; + taglibLookup.registerTaglib(require.resolve('../taglibs/core/marko.json')); taglibLookup.registerTaglib(require.resolve('../taglibs/layout/marko.json')); taglibLookup.registerTaglib(require.resolve('../taglibs/html/marko.json')); diff --git a/compiler/taglib-lookup/TaglibLookup.js b/compiler/taglib-lookup/TaglibLookup.js index 9df95b9a5..4473e39fe 100644 --- a/compiler/taglib-lookup/TaglibLookup.js +++ b/compiler/taglib-lookup/TaglibLookup.js @@ -141,6 +141,53 @@ class TaglibLookup { this._mergeNestedTags(taglib); } + forEachTag(callback) { + var tags = this.merged.tags; + if (tags) { + for (var tagName in tags) { + if (tags.hasOwnProperty(tagName)) { + var tag = tags[tagName]; + var result = callback(tag); + if (result === false) { + break; + } + } + } + } + } + + forEachAttribute(tagName, callback) { + var tags = this.merged.tags; + if (!tags) { + return; + } + + function findAttributesForTagName(tagName) { + var tag = tags[tagName]; + if (!tag) { + return; + } + + var attributes = tag.attributes; + if (!attributes) { + return; + } + + for (var attrName in attributes) { + if (attributes.hasOwnProperty(attrName)) { + callback(attributes[attrName], tag); + } + } + + if (tag.patternAttributes) { + tag.patternAttributes.forEach(callback); + } + } + + findAttributesForTagName(tagName); // Look for an exact match at the tag level + findAttributesForTagName('*'); // Including attributes that apply to all tags + } + getTag(element) { if (typeof element === 'string') { element = { @@ -157,7 +204,6 @@ class TaglibLookup { } getAttribute(element, attr) { - if (typeof element === 'string') { element = { tagName: element diff --git a/docs/compiler-api.md b/docs/compiler-api.md index 4bb89693f..15f5fa87c 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -1,6 +1,60 @@ The Compiler API ================ +# require('marko/compiler') + +## Methods + +### buildTaglibLookup(dirname) + +Returns a [TaglibLookup](#TaglibLookup) for discovering custom tags available to a template in the given directory. + +Example usage: + +```javascript +var taglibLookup = + require('marko/compiler').buildTaglibLookup('some/dir'); + +taglibLookup.forEachTag((tag) => { + console.log(tag.name); +}); + +taglibLookup.forEachAttribute('div', (attr) => { + console.log(attr.name); +}); +``` + +### compile(src, filename, options, callback) + +### compileFile(filename, options, callback) + +### createBuilder(options) + +### createWalker(options) + +### parseRaw(templateSrc, filename) + +## Properties + +### taglibLookup + +Returns a reference to the [taglib-lookup](#taglib-lookup) module. + +### taglibLoader + +### taglibFinder + + +# taglib-lookup + +## Methods + +### registerTaglib = registerTaglib; + +### buildLookup(dirname) + +### clearCache(); + # AST ## Node diff --git a/test/autotests/taglib-lookup/cache-lookup/test.js b/test/autotests/taglib-lookup/cache-lookup/test.js index 70af97850..e2525b312 100644 --- a/test/autotests/taglib-lookup/cache-lookup/test.js +++ b/test/autotests/taglib-lookup/cache-lookup/test.js @@ -1,6 +1,7 @@ var nodePath = require('path'); -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup1 = taglibLookup.buildLookup(nodePath.join(__dirname, 'foo')); var lookup2 = taglibLookup.buildLookup(nodePath.join(__dirname, 'foo')); var lookup3 = taglibLookup.buildLookup(nodePath.join(__dirname, 'foo/empty')); diff --git a/test/autotests/taglib-lookup/core-attributes/test.js b/test/autotests/taglib-lookup/core-attributes/test.js index a228c7e99..de1f90bf3 100644 --- a/test/autotests/taglib-lookup/core-attributes/test.js +++ b/test/autotests/taglib-lookup/core-attributes/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); // console.log('LOOKUP: ', Object.keys(lookup.attributes)); var ifAttr = lookup.getAttribute('div', 'if'); diff --git a/test/autotests/taglib-lookup/core-tag/test.js b/test/autotests/taglib-lookup/core-tag/test.js index 6494f6463..209eff1a1 100644 --- a/test/autotests/taglib-lookup/core-tag/test.js +++ b/test/autotests/taglib-lookup/core-tag/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); var ifTag = lookup.getTag('if'); expect(ifTag != null).to.equal(true); diff --git a/test/autotests/taglib-lookup/custom-tag/test.js b/test/autotests/taglib-lookup/custom-tag/test.js index b0c97e8a0..bf9574de2 100644 --- a/test/autotests/taglib-lookup/custom-tag/test.js +++ b/test/autotests/taglib-lookup/custom-tag/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); var tag = lookup.getTag('test-hello'); // console.log(Object.keys(lookup.tags)); diff --git a/test/autotests/taglib-lookup/de-dupe/test.js b/test/autotests/taglib-lookup/de-dupe/test.js index 775bb3273..90d641950 100644 --- a/test/autotests/taglib-lookup/de-dupe/test.js +++ b/test/autotests/taglib-lookup/de-dupe/test.js @@ -1,6 +1,7 @@ var nodePath = require('path'); -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'taglib-duplicate')); // The "duplicate-bar" tag was declared in the lower diff --git a/test/autotests/taglib-lookup/declared-and-dynamic-attrs/test.js b/test/autotests/taglib-lookup/declared-and-dynamic-attrs/test.js index 2a1e1333c..0244ddfa1 100644 --- a/test/autotests/taglib-lookup/declared-and-dynamic-attrs/test.js +++ b/test/autotests/taglib-lookup/declared-and-dynamic-attrs/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); // console.log(Object.keys(lookup.attributes)); var attr = lookup.getAttribute('test-dynamic-attribute', 'DYNAMIC'); diff --git a/test/autotests/taglib-lookup/forEachAttribute/expected.json b/test/autotests/taglib-lookup/forEachAttribute/expected.json new file mode 100644 index 000000000..ac7a91604 --- /dev/null +++ b/test/autotests/taglib-lookup/forEachAttribute/expected.json @@ -0,0 +1,10 @@ +[ + "name", + "age", + "foo-on-*", + "if", + "else-if", + "else", + "for", + "while" +] \ No newline at end of file diff --git a/test/autotests/taglib-lookup/forEachAttribute/marko.json b/test/autotests/taglib-lookup/forEachAttribute/marko.json new file mode 100644 index 000000000..eb44efed5 --- /dev/null +++ b/test/autotests/taglib-lookup/forEachAttribute/marko.json @@ -0,0 +1,12 @@ +{ + "": { + "@name": "string", + "@age": "integer", + "@foo-on-*": { + "pattern": true + } + }, + "": { + "@baz": "string" + } +} \ No newline at end of file diff --git a/test/autotests/taglib-lookup/forEachAttribute/test.js b/test/autotests/taglib-lookup/forEachAttribute/test.js new file mode 100644 index 000000000..ac91583b9 --- /dev/null +++ b/test/autotests/taglib-lookup/forEachAttribute/test.js @@ -0,0 +1,12 @@ +exports.check = function(markoCompiler, expect, helpers) { + var taglibLookup = markoCompiler.taglibLookup; + var lookup = taglibLookup.buildLookup(__dirname); + + var attrNames = []; + + lookup.forEachAttribute('foo', (attr) => { + attrNames.push(attr.name); + }); + + helpers.compare(attrNames, '.json'); +}; \ No newline at end of file diff --git a/test/autotests/taglib-lookup/forEachTag/expected.json b/test/autotests/taglib-lookup/forEachTag/expected.json new file mode 100644 index 000000000..64b42245c --- /dev/null +++ b/test/autotests/taglib-lookup/forEachTag/expected.json @@ -0,0 +1,33 @@ +[ + "*", + "foo", + "bar", + "assign", + "else", + "else-if", + "for", + "if", + "include", + "include-text", + "invoke", + "macro", + "macro-body", + "marko-preserve-whitespace", + "pre", + "script", + "style", + "textarea", + "unless", + "var", + "while", + "layout-use", + "layout-put", + "layout-placeholder", + "html-comment", + "async-fragment", + "async-fragments", + "async-fragment-placeholder", + "async-fragment-timeout", + "async-fragment-error", + "cached-fragment" +] \ No newline at end of file diff --git a/test/autotests/taglib-lookup/forEachTag/marko.json b/test/autotests/taglib-lookup/forEachTag/marko.json new file mode 100644 index 000000000..be36c43b2 --- /dev/null +++ b/test/autotests/taglib-lookup/forEachTag/marko.json @@ -0,0 +1,11 @@ +{ + "<*>": { + "@global-attribute": "boolean" + }, + "": { + "@name": "string" + }, + "": { + "@name": "string" + } +} \ No newline at end of file diff --git a/test/autotests/taglib-lookup/forEachTag/test.js b/test/autotests/taglib-lookup/forEachTag/test.js new file mode 100644 index 000000000..c60760b50 --- /dev/null +++ b/test/autotests/taglib-lookup/forEachTag/test.js @@ -0,0 +1,11 @@ +exports.check = function(markoCompiler, expect, helpers) { + var lookup = markoCompiler.buildTaglibLookup(__dirname); + + var tagNames = []; + + lookup.forEachTag((tag) => { + tagNames.push(tag.name); + }); + + helpers.compare(tagNames, '.json'); +}; \ No newline at end of file diff --git a/test/autotests/taglib-lookup/global-attrs/test.js b/test/autotests/taglib-lookup/global-attrs/test.js index 1b2bc5b31..375dd6fd6 100644 --- a/test/autotests/taglib-lookup/global-attrs/test.js +++ b/test/autotests/taglib-lookup/global-attrs/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); // console.log('LOOKUP: ', Object.keys(lookup.attributes)); var attrDef = lookup.getAttribute('test-dynamic-attributes', 'global-attribute'); diff --git a/test/autotests/taglib-lookup/nested-tags-attrs/test.js b/test/autotests/taglib-lookup/nested-tags-attrs/test.js index c0296c57d..2f8020ec6 100644 --- a/test/autotests/taglib-lookup/nested-tags-attrs/test.js +++ b/test/autotests/taglib-lookup/nested-tags-attrs/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); // console.log(Object.keys(lookup.attributes)); var attr = lookup.getAttribute('nested-foo', 'attr1'); diff --git a/test/autotests/taglib-lookup/nested-tags/test.js b/test/autotests/taglib-lookup/nested-tags/test.js index ff42319bc..2cfb7a15b 100644 --- a/test/autotests/taglib-lookup/nested-tags/test.js +++ b/test/autotests/taglib-lookup/nested-tags/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var lookup = taglibLookup.buildLookup(__dirname); var tag = lookup.getTag('nested-foo'); diff --git a/test/autotests/taglib-lookup/transformers-core-only/test.js b/test/autotests/taglib-lookup/transformers-core-only/test.js index 0d23dd9e6..003ea4742 100644 --- a/test/autotests/taglib-lookup/transformers-core-only/test.js +++ b/test/autotests/taglib-lookup/transformers-core-only/test.js @@ -1,7 +1,6 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var transformers = []; - - var lookup = taglibLookup.buildLookup(__dirname); lookup.forEachTagTransformer('div', function(transformer) { diff --git a/test/autotests/taglib-lookup/transformers-custom-node/test.js b/test/autotests/taglib-lookup/transformers-custom-node/test.js index 9eeb335f7..4f978f639 100644 --- a/test/autotests/taglib-lookup/transformers-custom-node/test.js +++ b/test/autotests/taglib-lookup/transformers-custom-node/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var transformers = []; var lookup = taglibLookup.buildLookup(__dirname); diff --git a/test/autotests/taglib-lookup/transformers/test.js b/test/autotests/taglib-lookup/transformers/test.js index 3e2bf40ef..fa845ee70 100644 --- a/test/autotests/taglib-lookup/transformers/test.js +++ b/test/autotests/taglib-lookup/transformers/test.js @@ -1,4 +1,5 @@ -exports.check = function(taglibLookup, expect) { +exports.check = function(markoCompiler, expect) { + var taglibLookup = markoCompiler.taglibLookup; var transformers; var lookup; // lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'fixtures/nested')); diff --git a/test/taglib-lookup-test.js b/test/taglib-lookup-test.js index ba52066a1..d799c2077 100644 --- a/test/taglib-lookup-test.js +++ b/test/taglib-lookup-test.js @@ -8,14 +8,14 @@ var expect = require('chai').expect; var nodePath = require('path'); require('../compiler'); var autotest = require('./autotest'); -var taglibLookup = require('../compiler').taglibLookup; +var markoCompiler = require('../compiler'); describe('taglib-lookup' , function() { var autoTestDir = nodePath.join(__dirname, 'autotests/taglib-lookup'); autotest.scanDir(autoTestDir, function run(dir, helpers, done) { var test = require(nodePath.join(dir, 'test.js')); - test.check(taglibLookup, expect); + test.check(markoCompiler, expect, helpers); done(); }); });