diff --git a/src/cli/crawl-specs.js b/src/cli/crawl-specs.js index 8dce9ea7..bb8b2c8d 100644 --- a/src/cli/crawl-specs.js +++ b/src/cli/crawl-specs.js @@ -32,13 +32,17 @@ const path = require('path'); const specs = require('browser-specs'); const webidlParser = require('./parse-webidl'); const cssDfnParser = require('../lib/css-grammar-parser'); -const fetch = require('../lib/util').fetch; -const requireFromWorkingDirectory = require('../lib/util').requireFromWorkingDirectory; -const completeWithAlternativeUrls = require('../lib/util').completeWithAlternativeUrls; -const isLatestLevelThatPasses = require('../lib/util').isLatestLevelThatPasses; -const processSpecification = require('../lib/util').processSpecification; -const { setupBrowser, teardownBrowser } = require('../lib/util'); const { generateIdlNames, saveIdlNames } = require('./generate-idlnames'); +const { + completeWithAlternativeUrls, + fetch, + getGeneratedIDLNamesByCSSProperty, + isLatestLevelThatPasses, + processSpecification, + requireFromWorkingDirectory, + setupBrowser, + teardownBrowser +} = require('../lib/util'); /** * Flattens an array @@ -129,7 +133,7 @@ async function crawlSpec(spec, crawlOptions) { } }); - // Parse extracted CSS definitions + // Parse extracted CSS definitions and add generated IDL attribute names Object.entries(result.css.properties || {}).forEach(([prop, dfn]) => { if (dfn.value || dfn.newValues) { try { @@ -139,6 +143,7 @@ async function crawlSpec(spec, crawlOptions) { dfn.valueParseError = e.message; } } + dfn.styleDeclaration = getGeneratedIDLNamesByCSSProperty(prop); }); Object.entries(result.css.descriptors || {}).forEach(([desc, dfn]) => { if (dfn.value) { diff --git a/src/lib/util.js b/src/lib/util.js index 6418fde7..a64f1e51 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -584,6 +584,57 @@ async function expandCrawlResult(crawl, baseFolder) { } +/** + * Retrieves the list of IDL attribute names that the CSS property generates + * per the CSSOM spec, see: + * https://drafts.csswg.org/cssom/#ref-for-css-property-to-idl-attribute + * + * @function + * @param {String} property CSS property name + * @return {Array(String)} An array of IDL attribute names, dashed attribute + * first, then camel-cased attribute if different, then webkit-cased attribute + * name if needed + */ +function getGeneratedIDLNamesByCSSProperty(property) { + // Converts a CSS property to an IDL attribute name per the CSSOM spec: + // https://drafts.csswg.org/cssom/#css-property-to-idl-attribute + function cssPropertyToIDLAttribute(property, lowercaseFirst) { + let output = ''; + let uppercaseNext = false; + if (lowercaseFirst) { + property = property.substr(1); + } + for (const c of property) { + if (c === '-') { + uppercaseNext = true; + } else if (uppercaseNext) { + uppercaseNext = false; + output += c.toUpperCase(); + } else { + output += c; + } + } + return output; + } + + // Start with dashed attribute + const res = [property]; + + // Add camel-cased attribute if different + const camelCased = cssPropertyToIDLAttribute(property, false); + if (camelCased !== property) { + res.push(camelCased); + } + + // Add webkit-cased attribute if needed + if (property.startsWith('-webkit-')) { + res.push(cssPropertyToIDLAttribute(property, true)); + } + + return res; +}; + + module.exports = { fetch, requireFromWorkingDirectory, @@ -593,5 +644,6 @@ module.exports = { processSingleSpecification, completeWithAlternativeUrls, isLatestLevelThatPasses, - expandCrawlResult + expandCrawlResult, + getGeneratedIDLNamesByCSSProperty }; diff --git a/tests/util.js b/tests/util.js index f0ff0c45..87024a77 100644 --- a/tests/util.js +++ b/tests/util.js @@ -1,7 +1,10 @@ const { assert } = require('chai'); const specs = require('browser-specs'); -const { isLatestLevelThatPasses } = require('../src/lib/util'); +const { + getGeneratedIDLNamesByCSSProperty, + isLatestLevelThatPasses +} = require('../src/lib/util'); describe('isLatestLevelThatPasses', () => { function getSpecAtLevel(level, flags) { @@ -76,4 +79,25 @@ describe('isLatestLevelThatPasses', () => { (s.seriesComposition === 'full'))); assert.isTrue(isLatestLevelThatPasses(spec, specs, s => s === spec)); }); -}); \ No newline at end of file +}); + + +describe('getGeneratedIDLNamesByCSSProperty', () => { + it('returns the camel-cased and dashed attribute names for "touch-action"', () => { + assert.deepEqual( + getGeneratedIDLNamesByCSSProperty('touch-action'), + ['touch-action', 'touchAction']); + }); + + it('returns the camel-cased, webkit-cased and dashed attribute names for "-webkit-background-clip"', () => { + assert.deepEqual( + getGeneratedIDLNamesByCSSProperty('-webkit-background-clip'), + ['-webkit-background-clip', 'WebkitBackgroundClip', 'webkitBackgroundClip']); + }); + + it('returns just the name for "display"', () => { + assert.deepEqual( + getGeneratedIDLNamesByCSSProperty('display'), + ['display']); + }); +});