[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# http://editorconfig.org\n\nroot = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\nmax_line_length = 100\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: giuseppeg\n"
  },
  {
    "path": ".gitignore",
    "content": "dist\nnode_modules\ncoverage\n.next\nwebsite/out\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nsudo: false\nnode_js:\n  - \"8\"\naddons:\n  apt:\n    packages:\n      - xvfb\nbefore_install:\n  - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0\n  - export PATH=\"$HOME/.yarn/bin:$PATH\"\ninstall:\n  - export DISPLAY=':99.0'\n  - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &\n  - yarn\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<img width=\"32\" alt=\"screen shot 2018-07-08 at 5 45 52 pm\" src=\"https://user-images.githubusercontent.com/711311/42420995-f0441c16-82d6-11e8-984d-2a194d1fe570.png\"  role=\"presentation\" />\n\n# Deterministic Style Sheets ✨\n\n[![Build Status](https://travis-ci.org/giuseppeg/dss.svg?branch=master)](https://travis-ci.org/giuseppeg/dss)\n[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\nDSS (Deterministic StyleSheets) is a component-oriented CSS authoring system that compiles to high-performance atomic CSS classes-based stylesheets.\n\nDSS works like CSS Modules except that styles resolution is deterministic, CSS is compiled to atomic classes and the final bundle is very small.\n\nRead more about how it works on the [website](https://giuseppeg.github.io/dss/).\n\n[**warning, this is an experimental project and might not be production ready**]\n\nThe repo comes with `examples`:\n\n```shell\ncd examples/cli\n# or cd examples/webpack\nnpm install\nnpm start\n```\n\n## Features\n\n* ⚡️ Automatic compilation to Atomic CSS classes and high-performance stylesheets\n* 🆎 Deterministic styles resolution: styles are always resolved in application order\n* 📦 Scoped Styles\n* 🌎 Framework and language agnostic\n* 🤝 Preprocessors friendly\n* 💻 Standalone CLI and support for Webpack 3 and 4 with automatic vendor prefixing\n* ✂️ CSS the Best Parts\n\n## Contributing\n\nDSS is developed as a monorepo thanks to lerna and yarn workspaces. Everything you need to know is in this repository.\n\nSince this is a side project and I don't want to burn out, I decided to disable the GitHub issues.\n\n### Bugs\n\nIf you find a bug please submit a pull request with a failing test or a fix, and good description for the issue.\n\n### Features request\n\nPlease submit a pull request with an RFC where you explain the why and the how you think this feature is useful. I'd be glad to start a conversation from there before moving on to implementation. Also please let me know if you would be up to implement the feature you are suggesting.\n\n### My code is crap\n\nI know, it is a side project and I didn't sweat the details. I am more than happy to discuss about a complete rewrite if the project becomes popular.\n\n## LICENSE\n\nMIT\n"
  },
  {
    "path": "acss-stats-tool/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "acss-stats-tool/README.md",
    "content": "# atomic-css-stats\n\nProvides stats on `.css` files size (gzipped and brotli). Also compiles the styles to atomic CSS classes for compariaon.\n\n```\nnpm i -g atomic-css-stats\n```\n\nAccepts a space separated list of paths or URL to css files.\n\n```\nacss-stats ./file.css https://example.com/bundle.css [...]\n```\n\nexample:\n\n```\n$ acss-stats https://abs.twimg.com/a/1532484778/css/t1/twitter_core.bundle.css\n\n  ==============\n| https://abs.twimg.com/a/1532484778/css/t1/twitter_core.bundle.css\n ==============\n\nOriginal file:\n\nSize: 182.72 KB\nGzipped size: 34.08 KB\nBrotli size: 28.95 KB\n\n---\n\nCompiled to atomic CSS classes:\n\nSize: 60.05 KB\nGzipped size: 15.48 KB\nBrotli size: 12.83 KB\n```\n\n\n## Contributing\n\nThis package is part of the [DSS monorepo](https://github.com/giuseppeg/dss#contributing).\n\n## License\n\nMIT\n"
  },
  {
    "path": "acss-stats-tool/cli.js",
    "content": "#!/usr/bin/env node\n\nconst fs = require('fs')\nconst path = require('path')\nconst { promisify } = require('util')\nconst fetch = require('isomorphic-fetch')\nconst getStats = require('./')\n\nfunction read(resource) {\n  if (/^https?:\\/\\//.test(resource)) {\n    return fetch(resource).then(r => r.text())\n  }\n\n  return promisify(fs.readFile)(path.resolve(resource))\n}\n\nconst resources = [...process.argv.slice(2)]\n\n\n;(async function () {\n  const stats = []\n  for (const resource of resources) {\n    if (!resources) {\n      console.error('Provide a valid path to file or url for ' + resource)\n      process.exit(1)\n    }\n\n    const content = await read(resource)\n    const s = await getStats(content)\n    stats.push({\n      resource,\n      stats: s,\n    })\n  }\n\n  stats.forEach(({ resource, stats }) => {\n    console.log(\n`\n ==============\n| ${resource}\n ==============\n\nOriginal file:\n\nSize: ${stats.original.size}\nGzipped size: ${stats.original.gzipSize}\nBrotli size: ${stats.original.brotliSize}\n\n---\n\nCompiled to atomic CSS classes:\n\nSize: ${stats.atomic.size}\nGzipped size: ${stats.atomic.gzipSize}\nBrotli size: ${stats.atomic.brotliSize}\n`)\n  })\n}());\n"
  },
  {
    "path": "acss-stats-tool/index.js",
    "content": "const filesize = require('filesize')\nconst gzipSize = require('gzip-size')\nconst brotliSize = require('brotli-size')\nconst mrmuh = require('murmurhash')\nconst hash = str => mrmuh(str, str.length).toString(36)\nconst postcss = require('postcss')\n\nexports = module.exports = async function getStats(content) {\n  const originalSize = filesize(content.length)\n  const atomizedContent = await atomizer(content)\n\n\n  return {\n    original: {\n      size: filesize(content.length),\n      gzipSize: filesize(gzipSize.sync(content)),\n      brotliSize:filesize(brotliSize.sync(content))\n    },\n    atomic: {\n      size: filesize(atomizedContent.length),\n      gzipSize: filesize(gzipSize.sync(atomizedContent)),\n      brotliSize: filesize(brotliSize.sync(atomizedContent)),\n    }\n  }\n}\n\nasync function atomizer(src) {\n  const processed = {}\n  let css = ''\n\n  function plugin() {\n    return root => {\n      root.walkDecls(decl => {\n          if (processed[decl.prop + decl.value]) return\n          processed[decl.prop + decl.value] = true\n          if (decl.prop.startsWith('-') && !decl.prop.startsWith('--') && css.endsWith('}')) {\n            css += `${css.substring(0, -1)}; ${decl.prop}: ${decl.value} }`\n          } else {\n            css += `.dss_${hash(decl.prop)}-${hash(decl.value)} { ${decl.prop}: ${decl.value} }`\n          }\n      })\n    }\n  }\n\n  return await postcss(plugin()).process(src, { from: undefined }).then(() => css)\n}\n\n"
  },
  {
    "path": "acss-stats-tool/package.json",
    "content": "{\n  \"name\": \"atomic-css-stats\",\n  \"version\": \"0.1.0-beta.4\",\n  \"description\": \"Provides information about regular and compiled to atomic CSS classes files size (gzipped)\",\n  \"main\": \"index.js\",\n  \"bin\": {\n    \"acss-stats\": \"cli.js\"\n  },\n  \"keywords\": [\n    \"dss\",\n    \"atomic css\",\n    \"css in js\",\n    \"css\",\n    \"classes\",\n    \"css modules\",\n    \"sass\",\n    \"postcss\",\n    \"classnames\"\n  ],\n  \"author\": \"Giuseppe Gurgone\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"brotli-size\": \"^0.0.2\",\n    \"filesize\": \"^3.6.1\",\n    \"gzip-size\": \"^5.0.0\",\n    \"isomorphic-fetch\": \"^2.2.1\",\n    \"murmurhash\": \"^0.0.2\",\n    \"postcss\": \"^7.0.1\"\n  }\n}\n"
  },
  {
    "path": "classnames/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "classnames/README.md",
    "content": "# dss-classnames\n\nDeterministic Style Sheets - classNames helper. Read [more about this package](https://dss-lang.com/usage/#dss-classnames).\n\n## Contributing\n\nThis package is part of the [DSS monorepo](https://github.com/giuseppeg/dss#contributing).\n\n## License\n\nMIT\n"
  },
  {
    "path": "classnames/index.js",
    "content": "/* eslint-disable no-var, prefer-arrow-callback */\n;(function(root) {\n  if (typeof module === 'object' && module.exports) {\n    module.exports = classnames\n  } else {\n    root.classnames = classnames\n  }\n\n  function setVal(processed, out, propValue) {\n    var prop\n    if (propValue.substr(0, 4) !== 'dss_') {\n      return propValue + ' ' + out\n    }\n    prop = propValue.substr(0, propValue.indexOf('-'))\n    if (!processed[prop]) {\n      processed[prop] = true\n      return out + ' ' + propValue\n    }\n    return out\n  }\n\n  function classnames() {\n    var groups = arguments\n    var processed = {}\n    var out = ''\n\n    for (var i = groups.length - 1; i >= 0; i--) {\n      var group = groups[i]\n      if (!group) {\n        continue\n      }\n      if (typeof group === 'string') {\n        out = setVal(processed, out, group)\n        continue\n      }\n      group.forEach(function(item) {\n        out = setVal(processed, out, item)\n      })\n    }\n\n    return out\n  }\n})(typeof self === 'undefined' ? this : self)\n"
  },
  {
    "path": "classnames/package.json",
    "content": "{\n  \"name\": \"dss-classnames\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"Deterministic Style Sheets - classNames helper\",\n  \"main\": \"index.js\",\n  \"keywords\": [\n    \"dss\",\n    \"atomic css\",\n    \"css in js\",\n    \"css\",\n    \"classes\",\n    \"css modules\",\n    \"sass\",\n    \"postcss\",\n    \"classnames\"\n  ],\n  \"author\": \"Giuseppe Gurgone\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "compiler/.gitignore",
    "content": "dist\nnode_modules\ncoverage\n"
  },
  {
    "path": "compiler/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "compiler/README.md",
    "content": "# dss-compiler\n\nDeterministic Style Sheets - compiler. Read [more about this package](https://dss-lang.com/usage/#dss-compiler).\n\n## Contributing\n\nThis package is part of the [DSS monorepo](https://github.com/giuseppeg/dss#contributing).\n\n## License\n\nMIT\n"
  },
  {
    "path": "compiler/bin/dss",
    "content": "#!/usr/bin/env node\n\nconst fs = require('fs')\nconst path = require('path')\nconst getopts = require(\"getopts\")\nconst glob = require('glob')\nconst dss = require('..')\nconst optimizer = require('../processor').optimizer\n\nconst read = filePath => fs.readFileSync(filePath, 'utf-8')\n\nconst args = getopts(process.argv.slice(2), {\n  alias: {\n    t: 'outType',\n    n: 'bundleName',\n    h: 'help'\n  },\n  default: {\n    outType: 'json',\n    bundleName: 'index.css',\n    help: false,\n  }\n})\n\nif (args._.length != 2 && !args.help) {\n  console.error('You must specifiy a glob pattern to find .css files and a target directory\\n')\n  args.help = true\n}\nif (args.help) {\n  const programName = process.argv[1].split('/').slice(-1).toString()\n  console.log([\n    'Usage:',\n    programName + ' <src-glob> <dest-path> [--bundleName<filename.css>] [--outType<json|js>]',\n    'Example:',\n    programName + ' ./src/**/*.css ./build --bundleName bundle.css --outType js',\n    ''\n  ].join('\\n\\n'))\n  process.exit(args._.length != 2 ? 1 : 0)\n}\n\nconst [globPattern, dist] = args._\n\nconst jsSheets = glob.sync(globPattern)\n\nif (jsSheets.length === 0) {\n  console.error('DSS: the glob ' + globPattern + ' did not match any files.')\n  process.exit(1)\n}\n\nconst compilePromises = jsSheets.map(filePath => {\n  const css = read(filePath)\n  return dss.singleton(css, { filePath, readableClass: process.env.NODE_ENV !== 'production' })\n})\n\nPromise.all(compilePromises).then(results => {\n  let flush\n  results.forEach((result, i) => {\n    const stringified = JSON.stringify(result.locals, null, 2)\n    const out = args.outType === 'js' ? `exports = module.exports = ${stringified}` : stringified\n    fs.writeFileSync(\n      path.resolve(path.join(dist, path.basename(jsSheets[i])+'.'+args.outType)),\n      out\n    )\n    flush = result.flush\n  })\n\n  const css = flush()\n  const destPath = path.resolve(path.join(dist, args.bundleName))\n  optimizer(css, { from: 'dss files', to: destPath })\n    .then(result => {\n      fs.writeFileSync(destPath, result.css)\n    })\n    .catch(e => { throw e })\n}).catch(e => {\n  console.error(e.reason ? `Error in: ${e.file}\\n\\n${e.reason}` : e)\n  process.exit(1)\n})\n"
  },
  {
    "path": "compiler/index.js",
    "content": "module.exports = require('./src')\n"
  },
  {
    "path": "compiler/package.json",
    "content": "{\n  \"name\": \"dss-compiler\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"Deterministic Style Sheets - compiler\",\n  \"main\": \"index.js\",\n  \"bin\": {\n    \"dss\": \"bin/dss\"\n  },\n  \"files\": [\n    \"bin\",\n    \"src\",\n    \"index.js\",\n    \"processor.js\",\n    \"LICENSE\",\n    \"README.md\"\n  ],\n  \"keywords\": [\n    \"dss\",\n    \"atomic css\",\n    \"css in js\",\n    \"css\",\n    \"classes\",\n    \"css modules\",\n    \"sass\",\n    \"postcss\",\n    \"classnames\"\n  ],\n  \"author\": \"Giuseppe Gurgone\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"test\": \"jest --coverage && npm run test:browser\",\n    \"test:browser\": \"run-p --race test:browser:server test:browser:run\",\n    \"test:browser:run\": \"browserify test/browser/index.js | tape-run\",\n    \"test:browser:server\": \"node test/browser/server.js\",\n    \"jest\": \"jest\"\n  },\n  \"dependencies\": {\n    \"autoprefixer\": \"8.6.4\",\n    \"getopts\": \"2.0.6\",\n    \"glob\": \"7.1.2\",\n    \"just-flatten-it\": \"2.0.0\",\n    \"postcss\": \"6.0.17\",\n    \"postcss-discard-duplicates\": \"2.1.0\",\n    \"postcss-js\": \"1.0.1\",\n    \"postcss-nest-atrules\": \"0.1.3\"\n  },\n  \"devDependencies\": {\n    \"browserify\": \"^16.1.1\",\n    \"dss-classnames\": \"0.1.0-beta.0\",\n    \"jest\": \"^22.4.3\",\n    \"npm-run-all\": \"^4.1.2\",\n    \"tape\": \"^4.9.0\",\n    \"tape-css\": \"^1.0.2-beta\",\n    \"tape-run\": \"^4.0.0\"\n  },\n  \"jest\": {\n    \"collectCoverageFrom\": [\n      \"src/**/*.{js}\",\n      \"!src/vendor/*\"\n    ]\n  }\n}\n"
  },
  {
    "path": "compiler/processor.js",
    "content": "module.exports = require('./src/processor')\n"
  },
  {
    "path": "compiler/src/compile.js",
    "content": "const flatten = require('just-flatten-it')\nconst hash = require('./vendor/hash')\n\n/* Fork of cxs with fundamendal changes */\n\nconst DEFAULT_SHEET_ID = '__defaultSheetId'\nconst cache = {}\nconst rules = {}\nconst insertedRules = {}\nconst insert = (sheetId, rule) => {\n  rules[sheetId].push(rule)\n}\nconst hyph = s => s.replace(/[A-Z]|^ms/g, '-$&').toLowerCase()\nconst mx = (rule, media) => (media ? `${media}{${rule}}` : rule)\nconst propVal = (prop, val) =>\n  (Array.isArray(val) ? val : [val]).map(val => `${hyph(prop)}:${val}`).join(';')\nconst rx = (cn, prop, val) => `${cn.startsWith(':') ? '' : '.'}${cn}{${propVal(prop, val)}}`\nconst rxArr = (cn, prop, vals) => `.${cn}{${propVal(prop, vals)}}`\nconst noAnd = s => s.replace(/&/g, '')\nconst combinatorOrPure = (className, child) => {\n  if (child.endsWith('&')) {\n    return `${noAnd(child)}.${className}`\n  }\n  return className + noAnd(child)\n}\n\nconst className = (sheetId, key, val, child, media) => {\n  const _key = key + val + child + media\n  const cached = cache[_key]\n  if (cached) {\n    const [className, rule] = cached\n    if (!insertedRules[sheetId][className]) {\n      insert(sheetId, rule)\n      insertedRules[sheetId][className] = true\n    }\n    return className\n  }\n  const className = `dss_${hash(key + media + child.replace(/[^\\w]+$/i, ''))}-${hash(\n    val.toString()\n  )}`\n  const rxFn = Array.isArray(val) ? rxArr : rx\n  const rule = mx(rxFn(combinatorOrPure(className, child), key, val), media)\n  cache[_key] = [className, rule]\n  insert(sheetId, rule)\n  insertedRules[sheetId][className] = true\n  return className\n}\n\nconst parse = (sheetId, obj, child = '', media, callback) =>\n  Object.keys(obj).map(key => {\n    const val = obj[key]\n    if (val === null) return ''\n    if (Object.prototype.toString.call(val) === '[object Object]') {\n      const m2 = key.charAt(0) === '@' ? key : null\n      const c2 = m2 ? child : child + key\n      return parse(sheetId, val, c2, m2 || media, callback)\n    }\n    return callback(sheetId, key, val, child, media)\n  })\n\nmodule.exports = (styles, opts = {}) => {\n  const sheetId = opts.sheetId || DEFAULT_SHEET_ID\n  if (!rules[sheetId]) {\n    rules[sheetId] = []\n    insertedRules[sheetId] = {}\n  }\n\n  return Object.keys(styles).reduce((acc, key) => {\n    // Insert non nested at rules like @keyframes as-is\n    // since they don't have selectors associated to them.\n    if (key.charAt(0) === '@') {\n      ;(Array.isArray(styles[key]) ? styles[key] : [styles[key]]).forEach(styles => {\n        const steps = {}\n        parse(sheetId, styles, '', null, (sheetId, prop, val, child) => {\n          const props = propVal(prop, val)\n          if (steps[child]) {\n            steps[child].push(props)\n          } else {\n            steps[child] = [props]\n          }\n        })\n        const css = Object.keys(steps).reduce((css, step) => {\n          css += mx(steps[step].join(';'), step)\n          return css\n        }, '')\n\n        insert(sheetId, mx(css, key))\n      })\n      return acc\n    }\n\n    const jsKey = key.replace(/^\\./, '')\n    acc[jsKey] = flatten(parse(sheetId, styles[key], undefined, undefined, className))\n    if (typeof opts.makeReadableClass === 'function') {\n      const readableClass = opts.makeReadableClass(jsKey)\n      acc[jsKey].unshift(readableClass)\n    }\n    return acc\n  }, {})\n}\n\nmodule.exports.css = (sheetId = DEFAULT_SHEET_ID) => (rules[sheetId] || []).sort().join('')\n\nmodule.exports.reset = (sheetId = DEFAULT_SHEET_ID) => {\n  if (rules[sheetId]) {\n    delete rules[sheetId]\n    delete insertedRules[sheetId]\n  }\n}\n"
  },
  {
    "path": "compiler/src/index.js",
    "content": "const path = require('path')\nconst { objectify } = require('postcss-js')\nconst hash = require('./vendor/hash')\nconst processor = require('./processor')\nconst compile = require('./compile')\n\nconst defaultOptions = {\n  filePath: undefined,\n  readableClass: false,\n}\n\nlet uuid = 1\n\nconst createDss = (singleton = false) => async (css, options = {}) => {\n  const opts = Object.assign({}, defaultOptions, options)\n\n  let makeReadableClass\n  if (opts.readableClass) {\n    if (typeof opts.readableClass === 'function') {\n      makeReadableClass = localName => opts.readableClass(localName, hash(css))\n    } else {\n      let prefix\n      if (typeof opts.filePath === 'string') {\n        const filename = path.basename(opts.filePath)\n        const p =\n          filename\n            .split('.')\n            .slice(0, -1)\n            .join('-') || 'DssSource'\n        prefix = p.charAt(0).toUpperCase() + p.substr(1)\n      } else {\n        prefix = 'DssSource'\n      }\n      makeReadableClass = localName => `${prefix}-${localName}-${hash(css)}`\n    }\n  }\n\n  const sheetId = String(singleton ? 0 : uuid++)\n  const result = await processor(css, { from: opts.filePath })\n  const locals = compile(objectify(result.root), {\n    makeReadableClass,\n    sheetId,\n  })\n\n  return {\n    locals,\n    css: () => compile.css(sheetId),\n    reset: () => compile.reset(sheetId),\n    flush: () => {\n      const css = compile.css(sheetId)\n      compile.reset(sheetId)\n      return css\n    },\n  }\n}\n\nmodule.exports = createDss()\nmodule.exports.singleton = createDss(true)\n"
  },
  {
    "path": "compiler/src/plugins/nest-pseudo.js",
    "content": "const postcss = require('postcss')\n\nmodule.exports = postcss.plugin('postcss-dss-nest-pseudo', () => {\n  return root => {\n    root.walkRules(rule => {\n      let parts = rule.selector.split(/:/)\n      if (parts.length < 2 || parts[0] === '&' || rule.selector.slice(-1) === '&') {\n        return\n      }\n\n      let parentSelector = parts[0]\n      let selector = ':' + parts.slice(1).join(':')\n      // :hover > .foo\n      if (parts[0] === '') {\n        const delimiter = selector.match(/[>~+]/)\n        if (delimiter) {\n          parts = selector.split(delimiter[0])\n          selector = `${parts[0].trim()} ${delimiter[0]} &`\n          parentSelector = parts[1].trim()\n        } else {\n          return\n        }\n      }\n\n      const clone = rule.clone()\n      clone.selector = selector\n      rule.nodes = [clone]\n      rule.selector = parentSelector\n    })\n  }\n})\n"
  },
  {
    "path": "compiler/src/plugins/sort-at-rules.js",
    "content": "const postcss = require('postcss')\n\n// Moves at rules at the bottom of the file.\n\nmodule.exports = postcss.plugin('postcss-dss-sort-at-rules', () => {\n  return root => {\n    const atRules = []\n    root.walkAtRules(atRule => {\n      atRules.push(atRule.clone())\n      atRule.remove()\n    })\n    root.nodes = root.nodes.concat(atRules)\n  }\n})\n"
  },
  {
    "path": "compiler/src/plugins/split-grouped-selectors.js",
    "content": "const postcss = require('postcss')\n\nmodule.exports = postcss.plugin('postcss-dss-split-grouped-selectors', () => {\n  return root => {\n    root.walkRules(rule => {\n      const selector = rule.selector.split(',').map(s => s.trim())\n      if (selector.length < 2) {\n        return\n      }\n      rule.selector = selector[0]\n      for (let i = 1; i < selector.length; i++) {\n        const clone = rule.clone()\n        clone.selector = selector[i]\n        rule.parent.insertAfter(rule, clone)\n      }\n    })\n  }\n})\n"
  },
  {
    "path": "compiler/src/plugins/validator.js",
    "content": "const postcss = require('postcss')\n\nconst shortHandProperties = [\n  'animation', 'background', 'border', 'border-bottom', 'border-left', 'border-radius', 'border-right', 'border-top', 'column-rule', 'columns', 'flex', 'flex-flow', 'font', 'grid', 'grid-area', 'grid-column', 'grid-row', 'grid-template', 'list-style', 'margin', 'offset', 'outline', 'overflow', 'padding', 'place-content', 'place-items', 'place-self', 'text-decoration', 'transition',\n]\n\nfunction error(node, message) {\n  throw node.error(\n    `DSS Error\n\n    ${message}\n\n    For a comprehensive list of supported features refer to http://giuseppeg.github.io/dss/supported-css-features/\n    `\n  )\n}\n\nmodule.exports = postcss.plugin('postcss-dss-validator', () => {\n  return root => {\n    const processed = {}\n    root.walkRules(rule => {\n      const { selector, parent } = rule\n      if (parent && parent.type === 'atrule') {\n        return\n      }\n\n      const params = parent && parent.params ? parent.params : ''\n\n      if (processed[params + selector]) {\n        error(rule,\n          `Detected duplicated selector: '${selector}'. Please merge it with the previous one.`\n        )\n      }\n      if (selector.split(',').length > 1) {\n        error(rule,\n          `Invalid selector: ${selector}. Selectors cannot be grouped.`\n        )\n      }\n      if (/::?(after|before|first-letter|first-line)/.test(selector)) {\n        error(rule,\n          `Detected pseudo-element: '${selector}'. Pseudo-elements are not supported. Please use regular elements.`\n        )\n      }\n\n      if (/:(matches|has|not|lang|any|current)/.test(selector)) {\n        error(rule,\n          `Detected unsupported pseudo-class: '${selector}'.`\n        )\n      }\n\n      const split = selector.split(/\\s*[+>~\\s]\\s*/g)\n\n      switch (split.length) {\n        case 2:\n          if (split[0].charAt(0) !== ':' || split[1].charAt(0) !== '.') {\n            error(rule,\n              `Invalid selector: ${selector}.`\n            )\n          }\n          break\n        case 1:\n          if (split[0].charAt(0) !== '.') {\n            error(rule,\n              `Invalid selector: ${selector}. Only class selectors are allowed.`\n            )\n          }\n          break\n        default:\n          error(rule,\n            `Invalid selector: ${selector}.`\n          )\n      }\n\n      if (/\\[/.test(selector)) {\n        error(rule,\n          `Invalid selector: ${selector}. Cannot use complex selectors, please use only class selectors.`\n        )\n      }\n      processed[params + selector] = true\n    })\n\n    root.walkDecls(decl => {\n      if (shortHandProperties.includes(decl.prop)) {\n        error(decl,\n          '`' + decl.prop + '`: DSS does\\'t support shorthand properties at the moment. This CSS feature will likely be supported in the future. Please expand your shorthand properties for now.' +\n          `\\n Can't remember what is the long form for \\`${decl.prop}\\`? Ask Google 👉  https://google.com/search?q=${encodeURIComponent(`css ${decl.prop} properties`)}`\n        )\n      }\n\n      if (decl.important) {\n        error(decl,\n          '!important is not allowed'\n        )\n      }\n    })\n  }\n})\n"
  },
  {
    "path": "compiler/src/processor.js",
    "content": "const postcss = require('postcss')\nconst nestAtRulesPlugin = require('postcss-nest-atrules')\nconst nestPseudoPlugin = require('./plugins/nest-pseudo')\nconst splitGroupedSelectorsPlugin = require('./plugins/split-grouped-selectors')\nconst validatorPlugin = require('./plugins/validator')\n\nconst processor = postcss([\n  splitGroupedSelectorsPlugin,\n  validatorPlugin,\n  nestAtRulesPlugin,\n  nestPseudoPlugin,\n])\nmodule.exports = (css, opts = { from: undefined }) => processor.process(css, opts)\n\nconst optimzr = postcss([\n  /* eslint-disable import/order */\n  require('postcss-discard-duplicates'),\n  require('autoprefixer'),\n  require('./plugins/sort-at-rules'),\n  /* eslint-enable import/order */\n])\n\nmodule.exports.optimizer = (css, opts = { from: undefined, to: undefined }) =>\n  optimzr.process(css, opts)\n"
  },
  {
    "path": "compiler/src/vendor/hash.js",
    "content": "// @flow\n// murmurhash2 via https://gist.github.com/raycmorgan/588423\n\nmodule.exports = function hashString(str) {\n  return hash(str, str.length).toString(36)\n}\n\nfunction hash(str, seed) {\n  let m = 0x5bd1e995\n  let r = 24\n  let h = seed ^ str.length\n  let length = str.length\n  let currentIndex = 0\n\n  while (length >= 4) {\n    let k = UInt32(str, currentIndex)\n\n    k = Umul32(k, m)\n    k ^= k >>> r\n    k = Umul32(k, m)\n\n    h = Umul32(h, m)\n    h ^= k\n\n    currentIndex += 4\n    length -= 4\n  }\n\n  switch (length) {\n    case 3:\n      h ^= UInt16(str, currentIndex)\n      h ^= str.charCodeAt(currentIndex + 2) << 16\n      h = Umul32(h, m)\n      break\n\n    case 2:\n      h ^= UInt16(str, currentIndex)\n      h = Umul32(h, m)\n      break\n\n    case 1:\n      h ^= str.charCodeAt(currentIndex)\n      h = Umul32(h, m)\n      break\n  }\n\n  h ^= h >>> 13\n  h = Umul32(h, m)\n  h ^= h >>> 15\n\n  return h >>> 0\n}\n\nfunction UInt32(str, pos) {\n  return (\n    str.charCodeAt(pos++) +\n    (str.charCodeAt(pos++) << 8) +\n    (str.charCodeAt(pos++) << 16) +\n    (str.charCodeAt(pos) << 24)\n  )\n}\n\nfunction UInt16(str, pos) {\n  return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8)\n}\n\nfunction Umul32(n, m) {\n  n = n | 0\n  m = m | 0\n  let nlo = n & 0xffff\n  let nhi = n >>> 16\n  let res = (nlo * m + (((nhi * m) & 0xffff) << 16)) | 0\n  return res\n}\n"
  },
  {
    "path": "compiler/test/__snapshots__/index.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`dss compiles 1`] = `\nObject {\n  \"a\": Array [\n    \"dss_rfc3hq-169mlyl\",\n    \"dss_16bwgo5-11z5xnj\",\n    \"dss_1u3exn4-nfznl2\",\n    \"dss_1u3exn4-1ysx8fe\",\n    \"dss_1qphpw1-hlr2nt\",\n  ],\n}\n`;\n\nexports[`dss compiles 2`] = `\n\"\n      .a { color: red; }\n      .a:hover { color: blue; }\n      @media screen and (min-width: 30px) {\n        .a { color: hotpink }\n      }\n\n      :hover > .a {\n        color: orange;\n      }\n\n      :hover + .a {\n        display: block;\n      }\n    \n\n⬇⬇⬇⬇\n\n.dss_1u3exn4-nfznl2:hover{color:blue}.dss_rfc3hq-169mlyl{color:red}:hover + .dss_1qphpw1-hlr2nt{display:block}:hover > .dss_1u3exn4-1ysx8fe{color:orange}@media screen and (min-width: 30px){.dss_16bwgo5-11z5xnj{color:hotpink}}\"\n`;\n\nexports[`dss compiles fallbacks 1`] = `\nObject {\n  \"a\": Array [\n    \"dss_rfc3hq-1t0ure0\",\n  ],\n}\n`;\n\nexports[`dss compiles fallbacks 2`] = `\n\"\n      .a {\n        color: red;\n        color: green;\n      }\n    \n\n⬇⬇⬇⬇\n\n.dss_rfc3hq-1t0ure0{color:red;color:green}\"\n`;\n\nexports[`dss compiles keyframes 1`] = `\nObject {\n  \"a\": Array [\n    \"dss_1q9w8i1-4hi1ll\",\n    \"dss_1ot5qnt-ykz8s4\",\n    \"dss_rwa454-yobcwj\",\n  ],\n}\n`;\n\nexports[`dss compiles keyframes 2`] = `\n\"\n      @font-face {\n        font-family: 'foo';\n        src: url(http://b.ar)\n      }\n      .a {\n        transition-property: fade;\n        transition-timing-function: ease-out;\n        transition-duration: 0.5s;\n      }\n      @keyframes some {0% { opacity:0 } 100% { opacity:1}}\n      @keyframes fade {0% { opacity:0 } 100% { opacity:1}}\n      @keyframes fade {\n        0% { opacity:0; margin-left: 0; }\n        100% { opacity:1; margin-left: 100; }\n      }\n    \n\n⬇⬇⬇⬇\n\n.dss_1ot5qnt-ykz8s4{transition-timing-function:ease-out}.dss_1q9w8i1-4hi1ll{transition-property:fade}.dss_rwa454-yobcwj{transition-duration:0.5s}@font-face{font-family:'foo';src:url(http://b.ar)}@keyframes fade{0%{opacity:0;margin-left:0}100%{opacity:1;margin-left:100}}@keyframes fade{0%{opacity:0}100%{opacity:1}}@keyframes some{0%{opacity:0}100%{opacity:1}}\"\n`;\n\nexports[`dss does not have duplicates 1`] = `\nObject {\n  \"bar\": Array [\n    \"dss_14e3233-hlr2nt\",\n  ],\n  \"foo\": Array [\n    \"dss_14e3233-hlr2nt\",\n  ],\n}\n`;\n\nexports[`dss does not have duplicates 2`] = `\".dss_14e3233-hlr2nt{display:block}\"`;\n"
  },
  {
    "path": "compiler/test/__snapshots__/objectify.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`objetify css media and pseudo 1`] = `\nObject {\n  \".a\": Object {\n    \"@media (min-width: 30px)\": Object {\n      \":hover\": Object {\n        \"color\": \"red\",\n      },\n    },\n  },\n}\n`;\n\nexports[`objetify css multiple 1`] = `\nObject {\n  \".a\": Object {\n    \":hover\": Object {\n      \"color\": \"blue\",\n    },\n    \"@media screen and (min-width: 30px)\": Object {\n      \"color\": \"hotpink\",\n    },\n    \"color\": \"red\",\n  },\n}\n`;\n\nexports[`objetify css pseudo class 1`] = `\nObject {\n  \".a\": Object {\n    \":hover\": Object {\n      \"color\": \"red\",\n    },\n  },\n}\n`;\n\nexports[`objetify css simple and pseudo class 1`] = `\nObject {\n  \".a\": Object {\n    \":hover\": Object {\n      \"color\": \"red\",\n    },\n    \"color\": \"pink\",\n  },\n}\n`;\n\nexports[`objetify css simple rule 1`] = `\nObject {\n  \".a\": Object {\n    \"color\": \"red\",\n  },\n}\n`;\n\nexports[`objetify css state-combinator-class 1`] = `\nObject {\n  \".a\": Object {\n    \":hover > &\": Object {\n      \"color\": \"blue\",\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "compiler/test/__snapshots__/processor.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`processor applies the nest-atrules plugin 1`] = `\n\"\n      .root {\n        color: red;\n      @media (min-width: 10px) {\n          display: block\n      }\n      }\n    \"\n`;\n\nexports[`processor applies the nest-pseudo plugin 1`] = `\n\"\n      .a {\n      :hover {\n        color: red;\n      }\n      }\n      .b {\n      :hover {\n        color: hotpink\n      }\n      }\n      .b {\n        color: hotpink\n      }\n      .c {\n        color: red;\n      }\n      .c {\n      :hover > & {\n        display: block;\n      }\n      }\n    \"\n`;\n\nexports[`processor applies the split-grouped-selectors plugin 1`] = `\n\"\n      .a {\n        color: red;\n      }\n      .b {\n        color: red;\n      }\n    \"\n`;\n\nexports[`processor merges rules 1`] = `\n\"\n      .root {\n      :hover {\n        color: yellow;\n      }\n      }\n\n      .block {\n        display: block;\n        margin-top: 10px;\n      }\n\n      .root {\n        color: red;\n        font-family: Verdana;\n        display: block;\n\n      @media (min-width: 600px) {\n          color: green\n      }\n      }\n\n      .test {\n        color: red;\n        color: pink;\n\n      @media (min-width: 600px) {\n          color: green;\n          color: yellow\n      }\n      }\n    \"\n`;\n\nexports[`processor mixed nest-atrules and nest-pseudo 1`] = `\n\"\n        .a {\n        :hover {\n      @media (min-width: 10px) {\n          color: red\n      }\n        }\n        }\n    \"\n`;\n\nexports[`processor moves at rules at the end of the file 1`] = `\n\"\n      div { color: red }\n      :hover > .foo { color: red }\n      @media (min-width: 1px) { body { color: red } }\n      @media (min-width: 10px) { body { color: gree } }\n    \"\n`;\n"
  },
  {
    "path": "compiler/test/browser/index.js",
    "content": "const test = require('tape-css')(require('tape'))\nconst classNames = require('dss-classnames')\nconst { compile, makeDom, run } = require('./utils')\n\nrun(async () => {\n  const {classes, styles} = await compile(`\n    .a { background-color: red }\n    .a:focus { background-color: yellow }\n    .b { background-color: green }\n    .c { background-color: red; display: block }\n    @media (min-width: 0px) {\n      .c {\n        background-color: green;\n        display: inline-block;\n      }\n      .d:focus { background-color: yellow }\n    }\n    .d { background-color: orange; font-weight: bold }\n    .f {\n      background-color: green;\n      background-color: invalid;\n    }\n  `)\n\n  const dom1 = makeDom(`\n    <div>\n      <div class=\"${classNames(classes.b, classes.a)}\"></div>\n      <div class=\"${classNames(classes.a, classes.b)}\"></div>\n    </div>\n  `)\n  test(\n    'resolves deterministically',\n    {\n      dom: dom1,\n      styles\n    },\n    t => {\n      t.equal(\n        getComputedStyle(dom1.children[0]).getPropertyValue('background-color'),\n        'rgb(255, 0, 0)',\n        'the first child should be rgb(255, 0, 0) i.e. red'\n      )\n      t.equal(\n        getComputedStyle(dom1.children[1]).getPropertyValue('background-color'),\n        'rgb(0, 128, 0)',\n        'the second child should be rgb(0, 128, 0) i.e. green'\n      )\n      t.end()\n    }\n  )\n\n  const dom2 = makeDom(`\n    <input class=\"${classNames(classes.a)}\" />\n  `)\n  test(\n    'works with pseudo selectors',\n    {\n      dom: dom2,\n      styles\n    },\n    t => {\n      t.equal(\n        getComputedStyle(dom2).getPropertyValue('background-color'),\n        'rgb(255, 0, 0)',\n        'initially it should be rgb(255, 0, 0) i.e. red'\n      )\n\n      dom2.focus()\n\n      t.equal(\n        getComputedStyle(dom2).getPropertyValue('background-color'),\n        'rgb(255, 255, 0)',\n        'on focus it should be rgb(255, 255, 0) i.e. yellow'\n      )\n      t.end()\n    }\n  )\n\n  const dom3 = makeDom(`\n    <input class=\"${classNames(classes.d, classes.c)}\" />\n  `)\n  test(\n    'works with media queries',\n    {\n      dom: dom3,\n      styles\n    },\n    t => {\n      const s = getComputedStyle(dom3)\n      t.equal(\n        s.getPropertyValue('background-color'),\n        'rgb(0, 128, 0)',\n        'initially `background-color` should be rgb(0, 128, 0) i.e. green'\n      )\n      t.equal(\n        s.getPropertyValue('display'),\n        'inline-block',\n        'initially `display` should be `inline-block`'\n      )\n      t.equal(\n        s.getPropertyValue('font-weight'),\n        'bold',\n        'initially `font-weight` should be `bold`'\n      )\n\n      dom3.focus()\n\n      t.equal(\n        getComputedStyle(dom3).getPropertyValue('background-color'),\n        'rgb(255, 255, 0)',\n        'on focus it should be rgb(255, 255, 0) i.e. yellow'\n      )\n      t.end()\n    }\n  )\n\n  const dom4 = makeDom(`\n    <input class=\"${classNames(classes.c, classes.d)}\" />\n  `)\n  test(\n    'works with merged rules',\n    {\n      dom: dom4,\n      styles\n    },\n    t => {\n      t.equal(\n        getComputedStyle(dom4).getPropertyValue('background-color'),\n        'rgb(0, 128, 0)',\n        'initially `background-color` should be rgb(0, 128, 0) i.e. green'\n      )\n\n      dom4.focus()\n\n      t.equal(\n        getComputedStyle(dom4).getPropertyValue('background-color'),\n        'rgb(255, 255, 0)',\n        'on focus it should be rgb(255, 255, 0) i.e. yellow'\n      )\n      t.end()\n    }\n  )\n\n  const dom5 = makeDom(`\n    <input class=\"${classNames(classes.a, classes.f)}\" />\n  `)\n  test(\n    'works with fallbacks',\n    {\n      dom: dom5,\n      styles\n    },\n    t => {\n      t.equal(\n        getComputedStyle(dom5).getPropertyValue('background-color'),\n        'rgb(0, 128, 0)',\n        'initially `background-color` should be rgb(0, 128, 0) i.e. green'\n      )\n      t.end()\n    }\n  )\n\n  const dom6 = makeDom(`\n    <input class=\"${classNames(classes.a, classes.f, 'Test')}\" />\n  `)\n  test(\n    'has readable class names',\n    {\n      dom: dom6,\n      styles\n    },\n    t => {\n      const matches = dom6.className.match(/(Test-[a|f]-)/g)\n\n      t.equal(\n        matches ? matches.length : 0,\n        2,\n        'should have Test-a-hash and Test-f-hash class names'\n      )\n      t.end()\n    }\n  )\n})\n"
  },
  {
    "path": "compiler/test/browser/server.js",
    "content": "const http = require('http')\nconst dss = require('../../').singleton\n\nconst port = process.env.PORT || 3000\n\nconst requestHandler = (request, response) => {\n  let css = ''\n\n  response.setHeader('Content-Type', 'application/json')\n  response.setHeader('Access-Control-Allow-Origin', '*')\n  response.setHeader('Access-Control-Request-Method', '*')\n  response.setHeader('Access-Control-Allow-Methods', 'POST')\n  response.setHeader('Access-Control-Allow-Headers', '*')\n\n  request.on('data', data => {\n    css += data\n  })\n\n  request.on('end', async () => {\n    const result = await dss(css, { readableClass: (localName, hash) => `Test-${localName}-${hash}` })\n    response.write(JSON.stringify({ classes: result.locals, styles: result.css() }))\n    response.end()\n  })\n}\n\nconst server = http.createServer(requestHandler)\n\nserver.listen(port, (err) => {\n  if (err) {\n    return console.log('something bad happened', err)\n  }\n\n  console.log(`server is listening on ${port}`)\n})\n"
  },
  {
    "path": "compiler/test/browser/utils.js",
    "content": "const tape = require('tape')\n\nmodule.exports.compile = function (css) {\n  return fetch('http://localhost:3000', {\n    body: css,\n    cache: 'no-cache',\n    method: 'POST',\n    redirect: 'follow',\n    referrer: 'no-referrer'\n  })\n  .then(response => response.json())\n  .catch(err => { throw err })\n}\n\nmodule.exports.makeDom = function (html) {\n  const fragment = document.createElement('div')\n  fragment.innerHTML = html\n  return fragment.children[0]\n}\n\nlet runCount = 1\nmodule.exports.run = function (fn) {\n  tape('suite ' + runCount++, t => {\n    const result = fn()\n    if (result instanceof Promise) {\n      result.then(() => {\n        t.end()\n      })\n    } else {\n      t.end()\n    }\n  })\n}\n"
  },
  {
    "path": "compiler/test/index.test.js",
    "content": "const dss = require('../')\n\ndescribe('dss', () => {\n  it('compiles', async () => {\n    const src = `\n      .a { color: red; }\n      .a:hover { color: blue; }\n      @media screen and (min-width: 30px) {\n        .a { color: hotpink }\n      }\n\n      :hover > .a {\n        color: orange;\n      }\n\n      :hover + .a {\n        display: block;\n      }\n    `\n    const { locals, flush } = await dss(src)\n\n    expect(locals).toMatchSnapshot()\n    expect(src + '\\n\\n⬇⬇⬇⬇\\n\\n' + flush()).toMatchSnapshot()\n  })\n\n  it('compiles fallbacks', async () => {\n    const src = `\n      .a {\n        color: red;\n        color: green;\n      }\n    `\n    const { locals, flush } = await dss(src)\n\n    expect(locals).toMatchSnapshot()\n    expect(src + '\\n\\n⬇⬇⬇⬇\\n\\n' + flush()).toMatchSnapshot()\n  })\n\n  it('works in async mode', async () => {\n    const styles1Promise = dss('.foo { color: red }')\n    const r1 = await dss('.bar { display: block }')\n    const css2 = r1.flush()\n    const r2 = await styles1Promise\n    const css1 = r2.flush()\n\n    expect(css2).toBeTruthy()\n    expect(css1).toBeTruthy()\n  })\n\n  it('does not have duplicates', async () => {\n    const { locals, css } = await dss('.foo { display: block } .bar { display: block }')\n    expect(locals).toMatchSnapshot()\n    expect(css()).toMatchSnapshot()\n  })\n\n  it('works as a singleton', async () => {\n    function rulesLength(css) {\n      return (css.match(/\\.dss_/g) || []).length\n    }\n\n    const call1 = await dss.singleton('.foo { display: block }')\n    expect(call1.locals.foo.length).toBe(1)\n    expect(rulesLength(call1.css())).toBe(1)\n\n    const call2 = await dss.singleton('.bar { display: block }')\n    expect(call2.locals.bar.length).toBe(1)\n    expect(rulesLength(call2.css())).toBe(1)\n\n    const call3 = await dss.singleton('.foo { color: red } .baz { color: orange }')\n    expect(call3.locals.foo.length).toBe(1)\n    expect(call3.locals.baz.length).toBe(1)\n    expect(rulesLength(call3.css())).toBe(3)\n\n    const call4 = await dss.singleton('.bar { vertical-align: middle }')\n    const css = call1.flush()\n    expect(rulesLength(call4.css())).toBe(0)\n    expect(rulesLength(css)).toBe(4)\n  })\n\n  it('compiles keyframes', async () => {\n    // @keyframes fade {0% { opacity:0 } 100% { opacity:1}}\n    const src = `\n      @font-face {\n        font-family: 'foo';\n        src: url(http://b.ar)\n      }\n      .a {\n        transition-property: fade;\n        transition-timing-function: ease-out;\n        transition-duration: 0.5s;\n      }\n      @keyframes some {0% { opacity:0 } 100% { opacity:1}}\n      @keyframes fade {0% { opacity:0 } 100% { opacity:1}}\n      @keyframes fade {\n        0% { opacity:0; margin-left: 0; }\n        100% { opacity:1; margin-left: 100; }\n      }\n    `\n    const { locals, flush } = await dss(src)\n\n    expect(locals).toMatchSnapshot()\n    expect(src + '\\n\\n⬇⬇⬇⬇\\n\\n' + flush()).toMatchSnapshot()\n  })\n})\n"
  },
  {
    "path": "compiler/test/objectify.test.js",
    "content": "const { parse } = require('postcss')\nconst { objectify } = require('postcss-js')\n\nconst compile = css => objectify(parse(css))\n\ndescribe('objetify css', () => {\n  it('simple rule', () => {\n    expect(\n      compile(`\n      .a { color: red }\n    `)\n    ).toMatchSnapshot()\n  })\n\n  it('pseudo class', () => {\n    expect(\n      compile(`\n      .a { :hover { color: red } }\n    `)\n    ).toMatchSnapshot()\n  })\n\n  it('simple and pseudo class', () => {\n    expect(\n      compile(`\n      .a { color: pink; :hover { color: red } }\n    `)\n    ).toMatchSnapshot()\n  })\n\n  it('media and pseudo', () => {\n    expect(\n      compile(`\n      .a { @media (min-width: 30px) { :hover { color: red } } }\n    `)\n    ).toMatchSnapshot()\n  })\n\n  it('multiple', () => {\n    expect(\n      compile(`\n      .a { color: red; }\n      .a { :hover { color: blue; } }\n      .a {\n        @media screen and (min-width: 30px) {\n          color: hotpink\n        }\n      }\n    `)\n    ).toMatchSnapshot()\n  })\n\n  it('state-combinator-class', () => {\n    expect(\n      compile(`\n      .a { :hover > & { color: blue; } }\n    `)\n    ).toMatchSnapshot()\n  })\n})\n"
  },
  {
    "path": "compiler/test/processor.test.js",
    "content": "const postcss = require('postcss')\nconst validatorPlugin = require('../src/plugins/validator')\nconst sortAtRulesPlugin = require('../src/plugins/sort-at-rules')\nconst processor = require('../src/processor')\n\ndescribe('processor', () => {\n  it('processes css', async () => {\n    const { css } = await processor(`\n      .root {\n        color: red;\n      }\n    `)\n    expect(css).not.toBe('')\n  })\n\n  it('applies the split-grouped-selectors plugin', async () => {\n    const { css } = await processor(`\n      .a, .b {\n        color: red;\n      }\n    `)\n    expect(css).toMatchSnapshot()\n  })\n\n  it('applies the nest-atrules plugin', async () => {\n    const { css } = await processor(`\n      .root {\n        color: red;\n      }\n      @media (min-width: 10px) {\n        .root {\n          display: block;\n        }\n      }\n    `)\n    expect(css).toMatchSnapshot()\n  })\n\n  it('applies the nest-pseudo plugin', async () => {\n    const { css } = await processor(`\n      .a:hover {\n        color: red;\n      }\n      .b:hover, .b {\n        color: hotpink\n      }\n      .c {\n        color: red;\n      }\n      :hover > .c {\n        display: block;\n      }\n    `)\n    expect(css).toMatchSnapshot()\n  })\n\n  it('mixed nest-atrules and nest-pseudo', async () => {\n    const { css } = await processor(`\n      @media (min-width: 10px) {\n        .a:hover {\n          color: red;\n        }\n      }\n    `)\n\n    expect(css).toMatchSnapshot()\n  })\n\n  it('merges rules', async () => {\n    const { css } = await processor(`\n      .root:hover {\n        color: yellow;\n      }\n\n      .block {\n        display: block;\n        margin-top: 10px;\n      }\n\n      @media (min-width: 600px) {\n        .root {\n          color: green;\n        }\n\n        .test {\n          color: green;\n          color: yellow;\n        }\n      }\n\n      .root {\n        color: red;\n        font-family: Verdana;\n        display: block;\n      }\n\n      .test {\n        color: red;\n        color: pink;\n      }\n    `)\n\n    expect(css).toMatchSnapshot()\n  })\n\n  describe('validation', () => {\n    const selectorsProcessor = css => postcss([validatorPlugin]).process(css, { from: undefined })\n\n    describe('throws when it detecs duplicated selectors', async () => {\n      it('simple', () =>\n        expect(\n          processor(`\n          .a { color: red }\n          .a { color: blue }\n        `)\n        ).rejects.toThrow(/Detected duplicated selector/))\n\n      it('combined', () =>\n        expect(\n          processor(`\n          .a, .a { color: red }\n        `)\n        ).rejects.toThrow(/Detected duplicated selector/))\n\n      it('except when it is a state declaration', () =>\n        expect(\n          processor(`\n          .a { color: red }\n          .a:hover { color: blue }\n        `)\n        ).resolves.toBeTruthy())\n    })\n\n    it('throws when selectors are grouped', () =>\n      expect(selectorsProcessor(`.a, .b { color: red }`)).rejects.toThrow(\n        /Selectors cannot be grouped/\n      ))\n\n    it('throws when using pseudo-elements', () => {\n      expect.assertions(8)\n      return Promise.all(\n        [\n          '.a:before',\n          '.a:after',\n          '.a:first-line',\n          '.a:first-letter',\n          '.a::before',\n          '.a::after',\n          '.a::first-line',\n          '.a:first-letter',\n        ].map(selector =>\n          expect(selectorsProcessor(`${selector} { color: red }`)).rejects.toThrow(\n            /Detected pseudo-element/\n          )\n        )\n      )\n    })\n\n    it('throws when using unsupported pseudo-classes', () => {\n      expect.assertions(6)\n      return Promise.all(\n        ['.a:matches(b)', '.a:has(b)', '.a:not(b)', '.a:lang(en)', '.a:any(b)', '.a:current'].map(\n          selector =>\n            expect(selectorsProcessor(`${selector} { color: red }`)).rejects.toThrow(\n              /Detected unsupported pseudo-class/\n            )\n        )\n      )\n    })\n\n    it('throws when using complex or non class selectors', async () => {\n      expect.assertions(8)\n      await Promise.all(\n        ['div', '[class]', '*'].map(selector =>\n          expect(selectorsProcessor(`${selector} { color: red }`)).rejects.toThrow(\n            /Invalid selector/\n          )\n        )\n      )\n      await Promise.all(\n        ['.a[href]', '.a .b', '.a *', '.a > .b', '.a + .b'].map(selector =>\n          expect(selectorsProcessor(`${selector} { color: red }`)).rejects.toThrow(\n            /Invalid selector/\n          )\n        )\n      )\n    })\n\n    it('does not throw when using state-combinator-class selectors', async () => {\n      expect.assertions(2)\n      await Promise.all(\n        [':hover > .foo', ':focus + .foo'].map(selector =>\n          expect(selectorsProcessor(`${selector} { color: red }`)).resolves.toEqual(\n            expect.objectContaining({ css: `${selector} { color: red }` })\n          )\n        )\n      )\n    })\n\n    it('does not throw when using keyframes', async () => {\n      expect.assertions(1)\n      expect(processor('@keyframes fade {0% { opacity:0 } 100% { opacity:1}}')).resolves.toEqual(\n        expect.objectContaining({ css: '@keyframes fade {0% { opacity:0 } 100% { opacity:1}}' })\n      )\n    })\n\n    it('throws an error when using a shorthand property', async () => {\n      expect(selectorsProcessor(`.a { background: red }`)).rejects.toThrow(\n        /support shorthand properties/\n      )\n    })\n\n    it('throws an error when using !important', async () => {\n      expect(selectorsProcessor(`.a { color: red ! important }`)).rejects.toThrow(\n        /!important is not allowed/\n      )\n    })\n  })\n\n  it('moves at rules at the end of the file', async () => {\n    const src = `\n      @media (min-width: 1px) { body { color: red } }\n      div { color: red }\n      @media (min-width: 10px) { body { color: gree } }\n      :hover > .foo { color: red }\n    `\n    const { css } = await postcss([sortAtRulesPlugin]).process(src, { from: undefined })\n    expect(css).toMatchSnapshot()\n  })\n})\n"
  },
  {
    "path": "examples/cli/a.css",
    "content": ".root:hover {\n  color: yellow;\n}\n\n.block {\n  display: block;\n  margin-top: 10px;\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: green;\n  }\n\n  .test {\n    color: green;\n    color: yellow;\n  }\n}\n\n.root {\n  color: red;\n  font-family: Verdana;\n  display: block;\n}\n\n.test {\n  color: red;\n  color: pink;\n}\n"
  },
  {
    "path": "examples/cli/b.css",
    "content": ".root {\n  color: blue;\n  font-family: monospace;\n  font-size: 2em;\n}\n\n@media (max-width: 400px) {\n  .root {\n    color: hotpink;\n  }\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: orange;\n  }\n}\n"
  },
  {
    "path": "examples/cli/d.css",
    "content": "@supports (color: yellow) {\n  .root {\n    color: yellow;\n  }\n}\n"
  },
  {
    "path": "examples/cli/index.html",
    "content": "<!doctype html>\n<link href=\"./index.css\" rel=\"stylesheet\" />\n<script src=\"./dss-classnames/index.js\"></script>\n\n<h1>Deterministic Style Sheets POF</h1>\n<main></main>\n\n<script>\n  Promise.all([\n    fetch('./a.css.json').then(c => c.json()),\n    fetch('./b.css.json').then(c => c.json()),\n    fetch('./d.css.json').then(c => c.json()),\n  ]).then(([a, b, d]) => {\n    console.log(a, b, d)\n     const root = document.querySelector('main')\n    root.innerHTML = `\n      <p class=\"${classnames(b.root, a.root)}\">hello</p>\n      <p class=\"${classnames(a.root, b.root)}\">hello</p>\n      <p class=\"${classnames()}\">hello</p>\n    `\n  })\n</script>\n"
  },
  {
    "path": "examples/cli/package.json",
    "content": "{\n  \"name\": \"dss-example-vanilla\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"rm -rf dist && mkdir dist && cp -R ./index.html node_modules/dss-classnames dist && dss '*.css' dist && serve dist\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dss-classnames\": \"0.1.0-beta.0\"\n  },\n  \"devDependencies\": {\n    \"dss-compiler\": \"0.1.0-beta.0\",\n    \"serve\": \"^7.0.0\"\n  }\n}\n"
  },
  {
    "path": "examples/webpack3/package.json",
    "content": "{\n  \"name\": \"dss-example-webpack3\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"webpack-dev-server\",\n    \"prod\": \"NODE_ENV=production webpack --config webpack.config.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dss-classnames\": \"0.1.0-beta.0\"\n  },\n  \"devDependencies\": {\n    \"dss-webpack\": \"0.1.0-beta.0\",\n    \"extract-text-webpack-plugin\": \"^3.0.2\",\n    \"html-webpack-plugin\": \"^2.0.0\",\n    \"webpack\": \"^3.0.0\",\n    \"webpack-dev-server\": \"^2.0.0\",\n    \"last-call-webpack-plugin\": \"^2.1.2\"\n  }\n}\n"
  },
  {
    "path": "examples/webpack3/src/a.css",
    "content": ".root:hover {\n  color: yellow;\n}\n\n.block {\n  display: block;\n  margin-top: 10px;\n  filter: blur(20px);\n  border-top-left-radius: 5px;\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: green;\n  }\n\n  .test {\n    color: green;\n    color: yellow;\n  }\n}\n\n.root {\n  color: red;\n  font-family: Verdana;\n  display: block;\n}\n\n.test {\n  color: red;\n  color: pink;\n}\n"
  },
  {
    "path": "examples/webpack3/src/b.css",
    "content": ".root {\n  color: blue;\n  font-family: monospace;\n  font-size: 2em;\n}\n\n@media (max-width: 400px) {\n  .root {\n    color: hotpink;\n  }\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: orange;\n  }\n}\n"
  },
  {
    "path": "examples/webpack3/src/d.css",
    "content": "@supports (color: yellow) {\n  .root {\n    color: yellow;\n  }\n}\n"
  },
  {
    "path": "examples/webpack3/src/index.html",
    "content": "<!doctype html>\n<link rel=\"stylesheet\" href=\"./index.css\">\n<h1>Deterministic Style Sheets POF</h1>\n<main></main>\n"
  },
  {
    "path": "examples/webpack3/src/index.js",
    "content": "const classNames = require('dss-classnames')\nconst a = require('./a.css')\nconst b = require('./b.css')\n\nconst root = document.querySelector('main')\n\nroot.innerHTML = `\n  <p class=\"${classNames(b.root, a.root)}\">hello</p>\n  <p class=\"${classNames(a.root, b.root)}\">hello</p>\n  <p class=\"${classNames()}\">hello</p>\n`\n"
  },
  {
    "path": "examples/webpack3/webpack.config.js",
    "content": "const path = require('path')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst ExtractTextPlugin = require('extract-text-webpack-plugin')\nconst DSSWebpackPlugin = require('dss-webpack')\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\n\nconst config = {\n  entry: path.resolve('./src/index.js'),\n  output: {\n    path: path.resolve('./dist'),\n    filename: '[name].js',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/,\n        use: ExtractTextPlugin.extract({\n          use: [\n            {\n              loader: DSSWebpackPlugin.loader,\n              query: {\n                localIdentName,\n              },\n            },\n          ],\n        }),\n      },\n    ],\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: path.resolve('./src/index.html'),\n    }),\n    new ExtractTextPlugin('index.css'),\n    new DSSWebpackPlugin({\n      test: /index\\.css$/,\n    }),\n  ],\n}\n\nmodule.exports = config\n"
  },
  {
    "path": "examples/webpack4/package.json",
    "content": "{\n  \"name\": \"dss-example-webpack4\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"webpack-dev-server\",\n    \"prod\": \"NODE_ENV=production webpack --config webpack.config.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dss-classnames\": \"0.1.0-beta.0\"\n  },\n  \"devDependencies\": {\n    \"dss-webpack\": \"0.1.0-beta.0\",\n    \"html-webpack-plugin\": \"^3.0.0\",\n    \"mini-css-extract-plugin\": \"^0.4.0\",\n    \"webpack\": \"^4.0.0\",\n    \"webpack-cli\": \"^2.0.15\",\n    \"webpack-dev-server\": \"^3.0.0\",\n    \"last-call-webpack-plugin\": \"^3.0.0\"\n  }\n}\n"
  },
  {
    "path": "examples/webpack4/src/a.css",
    "content": ".root:hover {\n  color: yellow;\n}\n\n.block {\n  display: block;\n  margin-top: 10px;\n  filter: blur(20px);\n  border-top-left-radius: 5px;\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: green;\n  }\n\n  .test {\n    color: green;\n    color: yellow;\n  }\n}\n\n.root {\n  color: red;\n  font-family: Verdana;\n  display: block;\n}\n\n.test {\n  color: red;\n  color: pink;\n}\n"
  },
  {
    "path": "examples/webpack4/src/b.css",
    "content": ".root {\n  color: blue;\n  font-family: monospace;\n  font-size: 2em;\n}\n\n@media (max-width: 400px) {\n  .root {\n    color: hotpink;\n  }\n}\n\n@media (min-width: 600px) {\n  .root {\n    color: orange;\n  }\n}\n"
  },
  {
    "path": "examples/webpack4/src/d.css",
    "content": "@supports (color: yellow) {\n  .root {\n    color: yellow;\n  }\n}\n"
  },
  {
    "path": "examples/webpack4/src/index.html",
    "content": "<!doctype html>\n<link rel=\"stylesheet\" href=\"./index.css\">\n<h1>Deterministic Style Sheets POF</h1>\n<main></main>\n"
  },
  {
    "path": "examples/webpack4/src/index.js",
    "content": "const classNames = require('dss-classnames')\nconst a = require('./a.css')\nconst b = require('./b.css')\n\nconst root = document.querySelector('main')\n\nroot.innerHTML = `\n  <p class=\"${classNames(b.root, a.root)}\">hello</p>\n  <p class=\"${classNames(a.root, b.root)}\">hello</p>\n  <p class=\"${classNames()}\">hello</p>\n`\n"
  },
  {
    "path": "examples/webpack4/webpack.config.js",
    "content": "const path = require('path')\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst DSSWebpackPlugin = require('dss-webpack')\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\nconst mode = process.env.NODE_ENV || 'development'\n\nconst config = {\n  mode,\n  entry: path.resolve('./src/index.js'),\n  output: {\n    path: path.resolve('./dist'),\n    filename: '[name].js',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/,\n        use: [\n          MiniCssExtractPlugin.loader,\n          {\n            loader: DSSWebpackPlugin.loader,\n            query: {\n              localIdentName,\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: path.resolve('./src/index.html'),\n    }),\n    new MiniCssExtractPlugin({\n      // Options similar to the same options in webpackOptions.output\n      // both options are optional\n      filename: 'index.css',\n    }),\n    new DSSWebpackPlugin({\n      test: /index\\.css$/,\n    }),\n  ],\n}\n\nmodule.exports = config\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"lerna\": \"2.11.0\",\n  \"packages\": [\n    \"classnames\",\n    \"compiler\",\n    \"next-dss\",\n    \"webpack\"\n  ],\n  \"version\": \"independent\",\n  \"command\": {\n    \"init\": {\n      \"exact\": true\n    }\n  },\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true\n}\n"
  },
  {
    "path": "next-dss/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "next-dss/README.md",
    "content": "# next-dss\n\nDeterministic Style Sheets - Next.js plugin. Read [more about this package](https://dss-lang.com/usage/#next-dss).\n\n## Contributing\n\nThis package is part of the [DSS monorepo](https://github.com/giuseppeg/dss#contributing).\n\n## License\n\nMIT\n"
  },
  {
    "path": "next-dss/index.js",
    "content": "const DSSWebpackPlugin = require('dss-webpack')\nconst ExtractTextPlugin = require('extract-text-webpack-plugin')\nconst cssLoaderConfig = require('@zeit/next-css/css-loader-config')\nconst commonsChunkConfig = require('@zeit/next-css/commons-chunk-config')\nconst escapeStringRegexp = require('escape-string-regexp')\n\nmodule.exports = (nextConfig = {}) => {\n  return Object.assign({}, nextConfig, {\n    webpack(config, options) {\n      if (!options.defaultLoaders) {\n        throw new Error(\n          'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade'\n        )\n      }\n\n      const { dev, isServer } = options\n      const { dssLoaderOptions } = nextConfig\n      // Support the user providing their own instance of ExtractTextPlugin.\n      // If extractCSSPlugin is not defined we pass the same instance of ExtractTextPlugin to all css related modules\n      // So that they compile to the same file in production\n      let extractCSSPlugin = nextConfig.extractCSSPlugin || options.extractCSSPlugin\n\n      const bundleName = dssLoaderOptions.filename || 'static/style.css'\n\n      if (!extractCSSPlugin) {\n        extractCSSPlugin = new ExtractTextPlugin({\n          filename: bundleName\n        })\n        config.plugins.push(extractCSSPlugin)\n        options.extractCSSPlugin = extractCSSPlugin\n        if (!isServer) {\n          config = commonsChunkConfig(config, /\\.css$/)\n        }\n      }\n\n      options.defaultLoaders.css = cssLoaderConfig(config, extractCSSPlugin, {\n        cssModules: true,\n        cssLoaderOptions: {},\n        dev,\n        isServer: false\n      }).map(loader => {\n        // Replace css-loader with the dss-loader\n\n        if (typeof loader.loader !== 'string' || !loader.loader.startsWith('css-loader')) {\n          return loader\n        }\n\n        return {\n          loader: DSSWebpackPlugin.loader,\n          query: {\n            localIdentName: dssLoaderOptions.localIdentName\n          }\n        }\n      })\n\n      config.module.rules.push({\n        test: /\\.css$/,\n        use: options.defaultLoaders.css\n      })\n\n      config.plugins.push(\n        new DSSWebpackPlugin({\n          test: new RegExp(escapeStringRegexp(bundleName))\n        })\n      )\n\n      if (typeof nextConfig.webpack === 'function') {\n        return nextConfig.webpack(config, options)\n      }\n\n      return config\n    }\n  })\n}\n"
  },
  {
    "path": "next-dss/package.json",
    "content": "{\n  \"name\": \"next-dss\",\n  \"version\": \"0.1.0-beta.0\",\n  \"main\": \"index.js\",\n  \"keywords\": [\n    \"dss\",\n    \"atomic css\",\n    \"css in js\",\n    \"css\",\n    \"classes\",\n    \"css modules\",\n    \"sass\",\n    \"postcss\",\n    \"classnames\",\n    \"react\",\n    \"next plugin\",\n    \"next.js\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dss-webpack\": \"0.1.0-beta.0\",\n    \"@zeit/next-css\": \"0.2.0\",\n    \"escape-string-regexp\": \"1.0.5\",\n    \"extract-text-webpack-plugin\": \"3.0.2\",\n    \"last-call-webpack-plugin\": \"2.1.2\"\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"Deterministic Style Sheets\",\n  \"keywords\": [],\n  \"author\": \"Giuseppe Gurgone\",\n  \"license\": \"MIT\",\n  \"workspaces\": [\n    \"classnames\",\n    \"compiler\",\n    \"examples/cli\",\n    \"examples/webpack*\",\n    \"webpack\",\n    \"website\"\n  ],\n  \"scripts\": {\n    \"test\": \"xo && cd compiler && npm test\",\n    \"lint\": \"xo\",\n    \"format\": \"prettier --single-quote --trailing-comma=es5 --no-semi --write all {src,test,*}/**/*.js\",\n    \"clean\": \"rm -rf node_modules **/node_modules **/**/node_modules **/dist **/**/dist website/.next website/out\"\n  },\n  \"devDependencies\": {\n    \"lerna\": \"2.11.0\",\n    \"prettier\": \"^1.11.1\",\n    \"push-dir\": \"^0.4.1\",\n    \"xo\": \"^0.20.3\"\n  },\n  \"xo\": {\n    \"envs\": [\n      \"node\",\n      \"browser\"\n    ],\n    \"extends\": [\n      \"prettier\"\n    ],\n    \"ignores\": [\n      \"compiler/src/vendor\",\n      \"examples\",\n      \"website\"\n    ],\n    \"rules\": {\n      \"capitalized-comments\": 0,\n      \"unicorn/import-index\": 0\n    },\n    \"globals\": [\n      \"describe\",\n      \"it\",\n      \"expect\"\n    ]\n  }\n}\n"
  },
  {
    "path": "release-website",
    "content": "#!/usr/bin/env bash\n\nrm -rf out\ncd website &&\nyarn export &&\ntouch out/.nojekyll &&\ntouch out/CNAME &&\necho \"dss-lang.com\" >> out/CNAME &&\n../node_modules/.bin/push-dir --dir=out --branch=gh-pages\n"
  },
  {
    "path": "webpack/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "webpack/README.md",
    "content": "# dss-webpack\n\nDeterministic Style Sheets - webpack loader and plugin for webpack 3 and 4. Read [more about this package](https://dss-lang.com/usage/#dss-webpack).\n\n## Contributing\n\nThis package is part of the [DSS monorepo](https://github.com/giuseppeg/dss#contributing).\n\n## License\n\nMIT\n"
  },
  {
    "path": "webpack/index.js",
    "content": "const optimizer = require('dss-compiler/processor').optimizer\n\nlet LastCallWebpackPlugin\ntry {\n  LastCallWebpackPlugin = require('last-call-webpack-plugin')\n} catch (error) {\n  if (/cannot find module/i.test(error.message)) {\n    throw new Error(`DSSWebpackPlugin depends on last-call-webpack-plugin.\n\nAre you Webpack 3 user?\nPlease install last-call-webpack-plugin@^2.0.0 as devDependency.\n\nAre you Webpack 4 user?\nPlease install last-call-webpack-plugin@^3.0.0 as devDependency.\n`)\n  }\n  throw error\n}\n\nconst PHASES = \"PHASE\" in LastCallWebpackPlugin ? \"PHASE\" : \"PHASES\";\n\nfunction processor(assetName, asset) {\n  const css = asset.source()\n  return optimizer(css, { from: assetName, to: assetName }).then(result => result.css)\n}\n\nclass DSSPlugin extends LastCallWebpackPlugin {\n  constructor(options = { canPrint: false }) {\n    super({\n      assetProcessors: [\n        {\n          phase: LastCallWebpackPlugin[PHASES].OPTIMIZE_ASSETS,\n          regExp: options.test || /\\.css$/g,\n          processor\n        },\n        {\n          phase: LastCallWebpackPlugin[PHASES].OPTIMIZE_CHUNK_ASSETS,\n          regExp: options.test || /\\.css$/g,\n          processor\n        }\n      ],\n      canPrint: options.canPrint\n    })\n  }\n\n  buildPluginDescriptor() {\n    return { name: 'DSSWebpackPlugin' }\n  }\n}\n\nDSSPlugin.loader = require.resolve('./loader')\n\nmodule.exports = DSSPlugin\n"
  },
  {
    "path": "webpack/loader.js",
    "content": "const loaderUtils = require('loader-utils')\nconst dss = require('dss-compiler')\n\nconst BANNER = '/* DSS file */'\n\nmodule.exports = function(content) {\n  if (this.cacheable) this.cacheable()\n  this.addDependency(this.resourcePath)\n  const callback = this.async()\n  const options = loaderUtils.getOptions(this) || {}\n  let readableClass\n  if (typeof options.localIdentName === 'string') {\n    const identName = loaderUtils.interpolateName(this, options.localIdentName, { content })\n    readableClass = localName => identName.replace(/\\[local]/g, localName)\n  }\n\n  dss(content, { readableClass })\n    .then(({ locals, flush }) => {\n      const moduleExports = [\n        BANNER,\n        `exports = module.exports = [[module.id, \"${flush()}\", \"\"]];`,\n        `exports.locals = ${JSON.stringify(locals)}`\n      ].join('\\n')\n      callback(null, moduleExports)\n    })\n    .catch(callback)\n}\n"
  },
  {
    "path": "webpack/package.json",
    "content": "{\n  \"name\": \"dss-webpack\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"Deterministic Style Sheets - webpack plugin and loader\",\n  \"main\": \"index.js\",\n  \"keywords\": [\n    \"dss\",\n    \"atomic css\",\n    \"css in js\",\n    \"css\",\n    \"classes\",\n    \"css modules\",\n    \"sass\",\n    \"postcss\",\n    \"classnames\",\n    \"webpack\",\n    \"react\"\n  ],\n  \"author\": \"Giuseppe Gurgone\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dss-compiler\": \"0.1.0-beta.0\",\n    \"loader-utils\": \"1.1.0\"\n  },\n  \"peerDependencies\": {\n    \"last-call-webpack-plugin\": \"^2.0.0 || ^3.0.0\"\n  }\n}\n"
  },
  {
    "path": "website/.babelrc",
    "content": "{\n  \"presets\": [\"next/babel\"],\n  \"plugins\": [[\"babel-plugin-classnames\", { \"packageName\": \"dss-classnames\"}]]\n}\n"
  },
  {
    "path": "website/LICENSE",
    "content": "Copyright 2018-present Giuseppe Gurgone.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "website/components/analytics/index.js",
    "content": "import React from 'react'\nimport ReactGA from 'react-ga'\n\nexport default class Analytics extends React.Component {\n  track = () => {\n    ReactGA.set({ page: this.props.route + window.location.hash })\n    ReactGA.pageview(this.props.route + window.location.hash)\n  }\n  componentDidMount() {\n    ReactGA.initialize(this.props.id)\n    this.track()\n    window.addEventListener('hashchange', this.track)\n  }\n  componentDidUpdate(prevProps) {\n    if (prevProps.route !== this.props.route) {\n      this.track()\n    }\n  }\n  componentWillUnmount() {\n    window.removeEventListener('hashchange', this.track)\n  }\n  render() {\n    return this.props.children\n  }\n}\n"
  },
  {
    "path": "website/components/body/index.css",
    "content": ".root {\n  margin-top: 0;\n  margin-bottom: 0;\n  margin-left: 0;\n  margin-right: 0;\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: 0;\n  padding-right: 0;\n  display: flex;\n  flex-direction: column;\n}\n"
  },
  {
    "path": "website/components/body/index.js",
    "content": "import styles from './index.css'\n\nexport default ({children}) => <body className={[styles.root]}>{children}</body>\n"
  },
  {
    "path": "website/components/heading/index.css",
    "content": ".tag {\n  display: block;\n  margin-top: 0;\n  margin-bottom: 0;\n  margin-left: 0;\n  margin-right: 0;\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: 0;\n  padding-right: 0;\n  font-family: $HeadingFontFamily;\n  font-size: $HeadingFontSize;\n  font-weight: $HeadingFontWeight;\n  color: $HeadingColor;\n}\n\n.content {\n  display: block;\n  margin-top: 2em;\n}\n\n.link {\n  color: inherit;\n}\n\n.size1 {\n  font-size: $u-fontSize1;\n  margin-top: 0;\n}\n\n.size2 {\n  font-size: $u-fontSize2;\n}\n\n.size3 {\n  font-size: $u-fontSize3;\n}\n\n.size4 {\n  font-size: $u-fontSize4;\n}\n\n.size5 {\n  font-size: $u-fontSize5;\n}\n\n.size6 {\n  font-size: $u-fontSize6;\n}\n"
  },
  {
    "path": "website/components/heading/index.js",
    "content": "import Link from '../link'\nimport styles from './index.css'\n\nconst defaultClassName = {\n  link: [],\n  tag: [],\n  content: [],\n}\n\nconst Wrap = ({children, className, href, target}) => {\n  if (!href) {\n    return children\n  }\n  return <Link href={href} className={className} target={target}>{children}</Link>\n}\n\nexport default ({children, className = defaultClassName, level = 1, size = 1, href = null, target = '_self', autolink = true}) => {\n  const Tag = `h${level}`\n  if (!href && autolink && level > 1) {\n    href = '#' + children.toLowerCase().replace(/[^a-z]/g, '-')\n  }\n  return (\n    <Wrap href={href} target={target} className={className.link}>\n      <Tag className={[styles.tag, href && styles.link, ...className.tag]}>\n        <span id={href && href.slice(1)} className={[styles.content, styles[`size${size}`], ...className.content]}>{children}</span>\n      </Tag>\n    </Wrap>\n  )\n}\n"
  },
  {
    "path": "website/components/layout/index.css",
    "content": ".container {\n  display: flex;\n  flex-wrap: wrap;\n  border-top-width: $SideBarSpacing;\n  border-top-style: solid;\n  border-top-color: $SideBarBackgroundColor;\n  min-height: 100vh;\n}\n\n.side {\n  display: flex;\n  flex-direction: row-reverse;\n  justify-content: space-between;\n  width: 100%;\n  box-sizing: border-box;\n  padding-top: $SideBarSpacing;\n  padding-bottom: $SideBarSpacing;\n  padding-left: $SideBarSpacing;\n  padding-right: $SideBarSpacing;\n  background-color: $SideBarBackgroundColor;\n  color: $SideBarColor;\n  max-width: 100%;\n}\n\n.sideOpen {\n  background-color: $SideBarStateBackgroundColor;\n}\n\n.logo {\n  font-size: $LogoSize;\n}\n\n.spacer {\n  height: $SideBarSpacing;\n}\n\n.navigationButton {\n  margin-top: $SideBarNavigationSpacing;\n  margin-bottom: $SideBarNavigationSpacing;\n  margin-left: 0;\n  margin-right: 0;\n}\n\n.playground {\n  margin-top: $u-spacing1;\n}\n\n.main {\n  flex-basis: 0%;\n  flex-grow: 1;\n  flex-shrink: 1;\n  background-color: $MainBackgroundColor;\n  max-width: 100%;\n}\n\n.mainContent {\n  background-color: $MainContentBackgroundColor;\n  color: $MainColor;\n  max-width: 960px;\n  min-height: 100%;\n  padding-top: $SideBarSpacing;\n  padding-bottom: $SideBarSpacing;\n  padding-left: $MainSpacing;\n  padding-right: $MainSpacing;\n}\n\n.starOnGithub {\n  width: 140px;\n  height: 20px;\n}\n\n@media (min-width: 680px) {\n  .container {\n    flex-wrap: nowrap;\n  }\n\n  .side {\n    width: auto;\n    flex-direction: column;\n    align-items: center;\n    justify-content: flex-start;\n  }\n}\n\n@media (min-width: 1025px) {\n  .mainContent {\n    position: relative;\n    padding-top: calc($LogoSize + $SideBarSpacing * 2);\n    padding-bottom: calc($LogoSize + $SideBarSpacing * 2);\n    padding-left: calc(($LogoSize + $SideBarSpacing * 2) * 0.9);\n    padding-right: calc(($LogoSize + $SideBarSpacing * 2) * 0.9);\n  }\n\n  .starOnGithub {\n    position: absolute;\n    top: $SideBarSpacing;\n    left: 50%;\n  }\n}\n"
  },
  {
    "path": "website/components/layout/index.js",
    "content": "import styles from './index.css'\nimport Link from '../link'\nimport Head from 'next/head'\nimport Logo from '../logo'\nimport Heading from '../heading'\nimport Navigation from '../navigation'\nimport Playground from '../playground'\nimport { LogoColor, LogoBackground } from '../../theme'\n\nexport default class Layout extends React.Component {\n  media = typeof window !== 'undefined' ? window.matchMedia('(min-width: 1150px)') : null\n\n  onMedia = ({matches}) => {\n    if (!this.state.isNavigationOpen && matches) {\n      this.setState({isNavigationOpen: true})\n    }\n    if (this.state.isNavigationOpen && !matches) {\n      this.setState({isNavigationOpen: false})\n    }\n  }\n\n  state = {\n    isNavigationOpen: false\n  }\n\n  toggle = e => {\n    e.preventDefault()\n    this.setState(({isNavigationOpen}) => ({ isNavigationOpen: !isNavigationOpen }))\n  }\n\n  componentDidMount() {\n    this.media = window.matchMedia('(min-width: 1150px)')\n    this.media.addListener(this.onMedia)\n    this.onMedia({ matches: this.media.matches })\n  }\n\n  componentWillUnmount() {\n    this.media.removeListener(this.onMedia)\n  }\n\n  render() {\n    const { children, title = 'Deterministic StyleSheets' } = this.props\n    const { isNavigationOpen } = this.state\n\n    return (\n      <React.Fragment>\n        <Head>\n          <title>{ `DSS | ${title}` }</title>\n          <meta charSet='utf-8'/>\n          <meta name='viewport' content='initial-scale=1.0, width=device-width'/>\n        </Head>\n\n        <div className={[styles.container]}>\n          <div className={[styles.side, isNavigationOpen && styles.sideOpen]}>\n            <div className={[styles.logo]}>\n              <Logo color={LogoColor} backgroundColor={LogoBackground} />\n            </div>\n            <div className={[styles.spacer]} />\n            <div className={[styles.navigation]}>\n              <Navigation open={isNavigationOpen} onPress={this.toggle} className={{ button: styles.navigationButton }} />\n            </div>\n          </div>\n          <main className={[styles.main]}>\n            <div className={[styles.mainContent]}>\n              <iframe\n                className={[styles.starOnGithub]}\n                src=\"https://ghbtns.com/github-btn.html?user=giuseppeg&repo=dss&type=star&count=true\"\n                frameBorder=\"0\"\n                scrolling=\"0\"\n              />\n              { children }\n              <div className={[styles.playground]}><Playground /></div>\n            </div>\n          </main>\n        </div>\n      </React.Fragment>\n    )\n  }\n}\n"
  },
  {
    "path": "website/components/link/index.css",
    "content": ".root {\n  color: $LinkColor;\n  font-family: $LinkFontFamily;\n  font-size: $LinkFontSize;\n  text-decoration-line: none;\n  font-weight: bold;\n}\n\n.root:hover,\n.root:focus {\n  color: $LinkStateColor;\n}\n"
  },
  {
    "path": "website/components/link/index.js",
    "content": "import _Link from 'next/link'\nimport styles from './index.css'\n\nconst Link = ({children, className = null, target, ...props}) => {\n  if (target && target === '_blank') {\n    return <a href={props.href} className={[styles.root, className]} target={target}>{children}</a>\n  }\n  return <_Link {...props}><a className={[styles.root, className]}>{children}</a></_Link>\n}\n\nexport default Link\n"
  },
  {
    "path": "website/components/logo/index.css",
    "content": ".root {\n  display: inline-block;\n  vertical-align: middle;\n  width: 1em;\n  height: 1em;\n  line-height: 1;\n  color: $LogoColor;\n}\n"
  },
  {
    "path": "website/components/logo/index.js",
    "content": "import styles from './index.css'\n\nexport default ({ size = undefined, color = '#fff', backgroundColor = '#000' }) => (\n  <svg className={[styles.root]} style={{ fontSize: size }} version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" x=\"0px\" y=\"0px\" viewBox=\"0 0 800 800\">\n    <g>\n      <polygon style={{fill: backgroundColor}} points=\"400,0.3 45.1,0.3 111,719.2 400,799.7 689,719.2 754.9,0.3  \"/>\n      <path style={{fill: color}} d=\"M188.9,145.7l6.2,88.9h102.2v0.2h223.2l-20.4,290.4L402.5,555l-97.7-29.9l-12-170.4h-89.3l16.7,237.6\n        l182.2,55.8l182.2-55.8l31.4-446.7H188.9z\"/>\n    </g>\n  </svg>\n)\n"
  },
  {
    "path": "website/components/markdown/index.css",
    "content": ".p {\n  font-family: $MarkdownPFontFamily;\n  font-size: $MarkdownPFontSize;\n  line-height: 1.5;\n  margin-top: $MarkdownPFontSize;\n  margin-bottom: $MarkdownPFontSize;\n}\n\n.p:first-child {\n  margin-top: 0\n}\n\n.p:last-child {\n  margin-bottom: 0\n}\n\n.code {\n  display: inline-block;\n  font-family: $MarkdownCodeFontFamily;\n  font-size: $MarkdownCodeFontSize;\n  color: $MarkdownCodeColor;\n  background-color: $MarkdownCodeBackgroundColor;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: calc($MarkdownCodeSpacing * 2);\n  padding-right: calc($MarkdownCodeSpacing * 2);\n  border-top-left-radius: $MarkdownCodeBorderRadius;\n  border-top-right-radius: $MarkdownCodeBorderRadius;\n  border-bottom-right-radius: $MarkdownCodeBorderRadius;\n  border-bottom-left-radius: $MarkdownCodeBorderRadius;\n  line-height: 1.4;\n  margin-top: 1px;\n  margin-bottom: 1px;\n}\n\n.codeBlock {\n  display: block;\n  width: 100%;\n  box-sizing: border-box;\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: 0;\n  padding-right: 0;\n  border-width: calc($MarkdownCodeSpacing * 4);\n  border-style: solid;\n  border-color: $MarkdownCodeBackgroundColor;\n  overflow-x: auto;\n}\n\n.inlineCodeBlock {\n  white-space: nowrap;\n}\n\n.ul {\n  font-family: $MarkdownULFontFamily;\n  font-size: $MarkdownULFontSize;\n  list-style-type: $MarkdownULListStyle;\n  line-height: 1.5;\n}\n"
  },
  {
    "path": "website/components/markdown/index.js",
    "content": "import Heading from '../heading'\nimport Link from '../link'\nimport styles from './index.css'\n\nconst headings = [1, 2, 3, 4, 5, 6].reduce((components, level) => {\n  components[`h${level}`] = props => <Heading {...props} level={level} size={level} />\n  return components\n}, {})\n\nconst p = ({children, ...props}) => <p className={[styles.p]}>{children}</p>\n\nconst Code = ({className = [], isBlock = true, ...props}) =>\n  <code {...props} className={[styles.code, isBlock ? styles.codeBlock : styles.inlineCodeBlock, className]} />\n\nconst inlineCode = props => <Code {...props} isBlock={false} />\n\nconst ul = ({children}) => <ul className={[styles.ul]}>{children}</ul>\n\nexport default {\n  ...headings,\n  a: Link,\n  p,\n  inlineCode,\n  code: Code,\n  ul,\n}\n"
  },
  {
    "path": "website/components/navigation/CurrentPath.js",
    "content": "import { createContext } from 'react'\nexport default createContext()\n"
  },
  {
    "path": "website/components/navigation/index.css",
    "content": ".button {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n  position: relative;\n  background-color: transparent;\n  background-image: none;\n  line-height: 0;\n  color: currentColor;\n  border-width: 2px;\n  border-style: solid;\n  border-color: transparent;\n  border-top-left-radius: $NavigationButtonBorderRadius;\n  border-top-right-radius: $NavigationButtonBorderRadius;\n  border-bottom-right-radius: $NavigationButtonBorderRadius;\n  border-bottom-left-radius: $NavigationButtonBorderRadius;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 2px;\n  padding-right: 2px;\n  outline-style: none;\n  width: $NavigationButtonSize;\n  height: $NavigationButtonSize;\n  user-select: none;\n  transition-property: border;\n  transition-duration: 0.2s;\n  transition-timing-function: ease;\n}\n\n.button:active,\n.button:focus:active {\n  border-top-width: 4px;\n  border-bottom-width: 4px;\n}\n\n.button:hover,\n.button:focus {\n  border-top-width: 0;\n  border-bottom-width: 0;\n}\n\n.buttonLine {\n  display: block;\n  width: calc($NavigationButtonSize - 4px);\n  height: 2px;\n  background-color: currentColor;\n}\n\n.menu {\n  display: none;\n  padding-top: $u-spacing4;\n}\n\n.menuOpen {\n  display: block;\n  position: relative;\n  animation-name: menuFade, menuSlide;\n  animation-duration: 0.3s, 0.2s;\n  animation-timing-function: ease-in, ease-in;\n}\n\n.section {\n  display: block;\n  margin-top: $u-spacing4;\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: $u-spacing4;\n  padding-right: $u-spacing4;\n  color: currentColor;\n  border-left-width: 2px;\n  border-left-style: solid;\n  border-left-color: transparent;\n  transition-property: border-color;\n  transition-timing-function: ease-out;\n  transition-duration: 0.3s;\n  outline-style: none;\n  font-weight: normal;\n  margin-left: 2px;\n}\n\n.section:focus-within,\n.section:hover,\n.section:focus,\n.sectionActive {\n  color: currentColor;\n  border-left-color: currentColor;\n}\n\n.section:first-child {\n  margin-top: 0;\n}\n\n.subSection {\n  margin-left: $u-spacing4;\n  position: relative;\n  left: 4px;\n}\n\n@keyframes menuFade {\n  0% { opacity: 0 }\n  100% { opacity: 1 }\n}\n\n@keyframes menuSlide {\n  0% { left: -100% }\n  80% { left: 30px }\n  100% { left: 0 }\n}\n"
  },
  {
    "path": "website/components/navigation/index.js",
    "content": "import styles from './index.css'\nimport Link from '../link'\nimport CurrentPath from './CurrentPath'\n\nconst NavLink = props => <CurrentPath.Consumer>{\n  currentPath =>\n    <Link {...props} className={[styles.section, currentPath === props.href && styles.sectionActive]} />\n}</CurrentPath.Consumer>\n\nconst Navigation = ({open, onPress, className = { button: null }}) => (\n  <React.Fragment>\n    <button aria-label=\"Toggle menu\" aria-controls=\"navigation-menu\" aria-expanded={open} onClick={onPress} className={[styles.button, className.button, open && styles.buttonOpen]}>\n      <span className={[styles.buttonLine]} />\n      <span className={[styles.buttonLine]} />\n      <span className={[styles.buttonLine]} />\n    </button>\n    <nav aria-label=\"Main navigation\" id=\"navigation-menu\" aria-hidden={!open} className={[styles.menu, open && styles.menuOpen]}>\n      <NavLink href='/'>About</NavLink>\n      <NavLink href='/usage'>Usage</NavLink>\n      <div className={[styles.section, styles.subSection]}>\n        <NavLink href='/usage#dss-compiler'>dss-compiler</NavLink>\n        <NavLink href='/usage#dss-classnames'>dss-classnames</NavLink>\n        <NavLink href='/usage#dss-webpack'>dss-webpack</NavLink>\n        <NavLink href='/usage#dss-next'>dss-next</NavLink>\n      </div>\n      <NavLink href='/#features'>Features</NavLink>\n      <div className={[styles.section, styles.subSection]}>\n        <NavLink href='/atomic-css'>Atomic CSS</NavLink>\n        <NavLink href='/how-it-works'>Determinism</NavLink>\n        <NavLink href='/classnames-helper'>The classNames helper</NavLink>\n        <NavLink href='/supported-css-features'>CSS features and rules</NavLink>\n        <NavLink href='/webpack'>Webpack</NavLink>\n        <NavLink href='/sass-preprocessors'>SASS and Preprocessors</NavLink>\n      </div>\n      <NavLink href='/examples'>Examples</NavLink>\n      <NavLink href='/static/playground/index.html' target=\"_blank\">Playground</NavLink>\n    </nav>\n  </React.Fragment>\n)\n\nexport default Navigation\n"
  },
  {
    "path": "website/components/playground/index.css",
    "content": ".container {\n  padding-top: 1em;\n  padding-right: 1em;\n  padding-bottom: 1em;\n  padding-left: 1em;\n  border-width: 1px;\n  border-style: solid;\n  border-color: $u-colorBlue;\n  border-top-left-radius: $u-borderRadius5;\n  border-top-right-radius: $u-borderRadius5;\n  border-bottom-right-radius: $u-borderRadius5;\n  border-bottom-left-radius: $u-borderRadius5;\n}\n\n.iframeWrapper {\n  position: relative;\n  width: 100%;\n  padding-top: 60%;\n  display: block;\n}\n\n.iframe {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border-top-width: 0;\n  border-right-width: 0;\n  border-bottom-width: 0;\n  border-left-width: 0;\n}\n\n.button {\n  background-color: $u-colorBlue;\n  color: $u-colorWhite;\n  font-family: $u-fontFamilyBase;\n  font-size: 1em;\n  border-top-width: 0;\n  border-right-width: 0;\n  border-bottom-width: 0;\n  border-left-width: 0;\n  border-top-left-radius: $u-borderRadius5;\n  border-top-right-radius: $u-borderRadius5;\n  border-bottom-right-radius: $u-borderRadius5;\n  border-bottom-left-radius: $u-borderRadius5;\n  padding-top: 0.5em;\n  padding-bottom: 0.5em;\n  padding-right: 1em;\n  padding-left: 1em;\n  display: block;\n  width: 100%;\n  cursor: pointer;\n}\n\n.link {\n  display: block;\n  margin-bottom: 1em;\n}\n"
  },
  {
    "path": "website/components/playground/index.js",
    "content": "import Link from '../link'\nimport styles from './index.css'\n\nexport default class Playground extends React.PureComponent {\n  state = {\n    isShown: false\n  }\n\n  render() {\n    if (this.state.isShown) {\n      return (\n        <div className={[styles.container]}>\n          <Link className={[styles.link]} href=\"/static/playground/index.html\" target=\"_blank\">\n            🔗 Open in new full screen window\n          </Link>\n          <div className={[styles.iframeWrapper]}>\n            <iframe src=\"/static/playground/index.html\" className={[styles.iframe]}/>\n          </div>\n        </div>\n      )\n    }\n\n    return (\n      <button className={[styles.button]} onClick={() => { this.setState({ isShown: true })}}>\n        Try DSS! Start the Playground 🎮\n      </button>\n    )\n  }\n}\n"
  },
  {
    "path": "website/md/atomic-css.md",
    "content": "# Atomic CSS classes and smaller bundles ⚡️ 📦\n\nThe DSS compiler converts every CSS declaration to an atomic CSS classes and returns a JSON object that contains mappings to the source rules.\n\nSince we are using atomic CSS classes, **declarations are deduped** and the final bundle size should be small. With atomic CSS classes the **file size growth is logarithmic** since DSS produces rules only for new declarations. This strategy also makes critical CSS extraction unnecessary.\n\n\n## How it works\n\nGiven some CSS:\n\n```css\n/* index.css */\n\n.foo {\n  display: flex;\n  flex-direction: column;\n  color: red;\n}\n\n.bar {\n  display: flex;\n  color: green;\n}\n```\n\nthe DSS compiler converts everything to atomic CSS classes and returns a `Promise` that resolves with an object that looks like the following:\n\n```\n{\n  locals,\n  css,\n  flush,\n}\n```\n\n\n### locals\n\n`locals` is an object where each `selector` is mapped to an array of atomic CSS classes:\n\n```JSON\n{\n \"foo\": [\n    \"dss_14e3233-fkmc3a\",\n    \"dss_1uacqdt-m23pbg\",\n    \"dss_rfc3hq-169mlyl\"\n  ],\n  \"bar\": [\n    \"dss_14e3233-fkmc3a\",\n    \"dss_rfc3hq-5rjgso\"\n  ]\n}\n```\n\nLocals should be written to disk as `json` as each CSS file is processed by DSS.\n\n### css\n\n`css` is a function that returns the generated CSS.\n\n```css\n/* css() */\n\n.dss_14e3233-fkmc3a{display:flex}\n.dss_1uacqdt-m23pbg{flex-direction:column}\n.dss_rfc3hq-169mlyl{color:red}\n.dss_rfc3hq-5rjgso{color:green}\n```\n\nWhen compiling multiple files `css` should be called at the end, only after all the files have been processed. This is because DSS collects rules as the files are processed.\n\n### flush\n\n`flush` is like `css` except that it resets the internal collection of styles. When calling `css` multiple times you always get the latest styles. Instead if you call `flush` subsequent calls of either `css` or `flush` will return an empty string.\n\n```\ncss()\n// .dss_14e3233-fkmc3a{display:flex}\ncss()\n// .dss_14e3233-fkmc3a{display:flex}\n\nflush()\n// .dss_14e3233-fkmc3a{display:flex}\n\ncss()\n// ''\n\nflush()\n// ''\n```\n\n### Putting everything together\n\n```\nconst fs = require('fs')\nconst dss = require('dss-compiler').singleton\n\nlet getCSS\n\nconst source1 = fs.readFileSync('./component1/styles.css')\n\nconst first = dss(source).then(({ locals }) => {\n  // locals contains the JSON above\n  fs.writeFileSync('./component1/styles.css.json', JSON.stringify(locals))\n})\n\nconst source2 = fs.readFileSync('./component2/styles.css')\n\nconst second = dss(source).then(({ locals, css, flush }) => {\n  fs.writeFileSync('./component2/styles.css.json', JSON.stringify(locals))\n\n  getCSS = flush\n})\n\nPromise.all([first, second]).then(() => {\n  fs.writeFileSync('./bundle.css', getCSS())\n})\n```\n\nWhen compiling multiple files, the JSON for each file should be written to disk and at the end of the compilation the CSS generated by DSS is available via a dss' `css()` call. The string returned by `css` contains the entire app CSS.\n\n**Note** that DSS comes with a CLI and a Webpack loader/plugin that automates the process above, so that you can chill and just focus on writing styles!\n"
  },
  {
    "path": "website/md/classnames-helper.md",
    "content": "# The classNames helper 📇\n\nSimilarly to CSS Modules, DSS generates mappings of `selector`-`array of atomic classes` and writes this information to a `json` file:\n\n```JSON\n{\n \"foo\": [\n    \"dss_rfc3hq-169mlyl\"\n  ],\n  \"bar\": [\n    \"dss_rfc3hq-5rjgso\"\n  ]\n}\n```\n\nOnce we have this information we can write a simple `classNames` helper that accepts a comma separated list of class references (`foo` and `bar` in the example) and **merges them right to left**:\n\n```js\nclassNames(styles.foo, styles.bar)\n\n// dss_rfc3hq-5rjgso\n\nclassNames(styles.bar, styles.foo)\n\n// dss_rfc3hq-169mlyl\n```\n\nThis is similar to how `Object.assign` works in JavaScript, except that we are merging lists of atomic CSS classes.\n\nBy merging these lists of atomic CSS classes right to left we can guarnatee that the final subset of classes applied to an element is predictable regardless of where the styles are defined.\n\nIf you use JavaScript you don't need to implement the `classNames` helper since we provide a ready to use package https://www.npmjs.com/package/dss-classnames\n\n## Implementing a classNames helper\n\nYou might want to take a look at the JavaScript implementation of classNames:\n\nhttps://github.com/giuseppeg/dss/tree/master/classnames\n"
  },
  {
    "path": "website/md/examples.md",
    "content": "# Examples\n\nThe most comprehensive example is this website which is styled with DSS. Feel free to take a look at its implementation https://github.com/giuseppeg/dss/tree/master/website\n\n* [CLI example](https://github.com/giuseppeg/dss/tree/master/examples/cli)\n* [webpack 3 example](https://github.com/giuseppeg/dss/tree/master/examples/webpack3)\n* [webpack 4 example](https://github.com/giuseppeg/dss/tree/master/examples/webpack4)\n* [Next.js (React) and PostCSS](https://github.com/giuseppeg/dss/tree/master/website)\n\n"
  },
  {
    "path": "website/md/how-it-works.md",
    "content": "# Deterministic styles resolution 🆎\n\nDSS' mission is to provide confidence when authoring CSS. This is done by resolving styles (selectors) in a deterministic way based on the application order of each class name. We think that it is very important to get a predictable result when applying two classes to an element.\n\nDeterminism can be achieved thanks to atomic CSS classes. DSS converts declarations to atomic CSS classes. This is done by hashing each property and value and building a class name like the following:\n\n```\ndss_<hash(property)>-<hash(value)>\n```\n\nFor example `color: red` is always hashed to:\n\n```\ndss_rfc3hq-169mlyl\n```\n\nand `color: green` to:\n\n\n```\ndss_rfc3hq-5rjgso\n```\n\nThe first part of these class names is the same: `dss_rfc3hq-` and this is information is used to resolve styles.\n\nGiven two CSS rules:\n\n```css\n.foo {\n  color: red;\n}\n\n.bar {\n  color: green;\n}\n```\n\nDSS compiles them to the following class names:\n\n```JSON\n{\n \"foo\": [\n    \"dss_rfc3hq-169mlyl\"\n  ],\n  \"bar\": [\n    \"dss_rfc3hq-5rjgso\"\n  ]\n}\n```\n\nOnce we have this information we can write a simple `classNames` helper that accepts a comma separated list of class references (`foo` and `bar` in the example) and merges them right to left:\n\n```js\nclassName(styles.foo, styles.bar)\n\n// dss_rfc3hq-5rjgso\n\nclassName(styles.bar, styles.foo)\n\n// dss_rfc3hq-169mlyl\n```\n\nThis is similar to how `Object.assign` works in JavaScript, except that we are merging lists of atomic CSS classes.\n"
  },
  {
    "path": "website/md/index.md",
    "content": "import Playground from '../components/playground'\n\n# DSS ✨\n\nDSS (_Deterministic StyleSheets_) is a component-oriented CSS authoring system that compiles to high-performance _atomic CSS classes_-based stylesheets.\n\nDSS works like CSS Modules except that supports [a subset of CSS](/supported-css-features) that can be compiled to atomic CSS classes. Thanks to atomic CSS classes styles can be resolved in a deterministic way based on their application order:\n\n```html\n<!-- the text will be green -->\n<div class=\"red green\">hello</div>\n\n<!-- the text will be red -->\n<div class=\"green red\">hello</div>\n```\n\n<Playground />\n\n## Features\n\n* ⚡️ Automatic compilation to Atomic CSS classes and high-performance stylesheets\n* 🆎 Deterministic styles resolution: styles are always resolved in application order\n* 📦 Scoped Styles\n* 🌎 Framework and language agnostic\n* 🤝 Preprocessors friendly\n* 💻 Standalone CLI and support for Webpack 3 and 4 with automatic vendor prefixing\n* ✂️ CSS the Best Parts\n\n## How it works\n\nThanks to the DSS compiler and a simple `classNames` helper, DSS styles are resolved in deterministic way that respects the application order.\n\nDSS is language agnostic. Styles are authored in static `.css` files, compiled down to atomic CSS classes for smaller bundle size and then consumed in any language (Ruby, PHP, Python etc) that implements the super simple `classNames` helper.\n\nGiven two class names that set the `color` to `red` and `green`:\n\n```css\n.foo {\n  color: red;\n}\n.bar {\n  color: green;\n}\n```\n\nwhen applied to an element one class wins over the other depending on the order in which the classes are applied:\n\n```html\n<!-- the text will be green -->\n<div class=\"foo bar\">hello</div>\n\n<!-- the text will be red -->\n<div class=\"bar foo\">hello</div>\n```\n\nSuch a feature makes it possible to tell with **confidence** which rules apply or overrule others at any given point in time.\n\nRead more about [how it works](/how-it-works).\n\nThis website is styled with DSS and its source code is available on [GitHub](https://github.com/giuseppeg/dss/tree/master/website). We also have a handful of [examples](https://github.com/giuseppeg/dss/tree/master/examples).\n"
  },
  {
    "path": "website/md/sass-preprocessors.md",
    "content": "# SASS and Preprocessors 💪\n\nWe 💙 <img alt=\"sass\" src=\"/static/sass.png\" style={{ height: '2em', marginLeft: 5, verticalAlign: '-0.1em' }} /> <img alt=\"postcss\" src=\"/static/postcss.svg\" style={{ height: '2em', marginLeft: 10, verticalAlign: '-0.1em' }} />\n\nSince DSS is just CSS you can use any preprocessor before your code is compiled with the [DSS compiler](/usage#dss-compiler).\n\nTo setup SASS or PostCSS with DSS and Webpack please refer to the [webpack page](/webpack#with-sass).\n"
  },
  {
    "path": "website/md/supported-css-features.md",
    "content": "# CSS features and rules ✂️\n\n**DSS supports a subset of CSS that makes it possible to compile down to atomic CSS classes**.\n\nGenerally DSS allows **single class selectors** however there are some exceptions where a higher specificity is actually necessary, this is the case for **states and at-rules which are supported as well**.\n\nBelow is a comprehensive list of features:\n\n## Supported\n\n* Class selectors: `.foo`\n* CSS states: `:hover`, `:active`, `:focus`, `:visited`, `:focus-within`, `:checked`, `:disabled`, `:required` etc.\n* At-rules like `@media`, `@supports`, `@keyframes`, `@font-face`\n* State-combinator-selector like `:hover > .foo` or `:focus + .bar`\n* `:nth-child`, `:first-child` etc.\n\n## Not supported\n\n* Element, id, universal and attribute selectors\n* Descendants selectors `.foo .bar`\n* Class-combinator-class selectors `.foo > .bar`\n* Not shallow (complex) selectors like `:hover > .foo + .bar`\n* Pseudo elements like `:after` and `:before` since regular elements can be used instead\n* `:has()`, `:matches()`, `:not()` etc.\n* Short hand properties like `background`, `border` need to be written in the long form. In the future we might allow them and unwrap them for you automatically ... thank you for your patience 🙏\n* `!important`\n\n"
  },
  {
    "path": "website/md/usage.md",
    "content": "# Usage 🔋\n\nTo its core DSS is a simple compiler that takes [regular CSS files](/supported-css-features) and generates atomic CSS classes.\n\n## Pre-requisites\n\nThe compiler is written in JavaScript and therefore you will need [Node.js](https://nodejs.org) v7.6+ installed on your machine.\n\nPlease read the [how it works](/how-it-works) page before you continue.\n\n## dss-compiler\n\n**required** - The DSS compiler.\n\nAdd the compiler to your project:\n\n```\nnpm i dss-compiler\n```\n\nThe easiest way to use the DSS compiler is via the CLI tool which accepts a [`glob`](https://www.npmjs.com/package/glob) to match your css files to compile, a `dist` folder and an optional bundle filename (by default it would write to `index.css`):\n\n```\ndss ./components/*.css ./build --bundleName bundle.css\n```\n\nThis will generate a `bundle.css` in the `build` folder. You can then include this bundle to your app using a simple `link` tag.\n\nDSS will also write the atomic CSS classnames mappings to JSON files to the same `build` folder. For example when compiling `components/button/styles.css` DSS writes `build/components/button/styles.css.json`. This file contains mappings of selector-array of atomic classes.\n\nOptionally DSS can generate JavaScript modules instead of JSON files. Prefer this option if you are consuming the mappings in a JavaScript application since this allows you to import from `components/button/styles.css` right away.\n\n```\ndss ./components/*.css ./build --bundleName bundle.css --outType js\n```\n\n### dss-compiler as a library\n\nThe compiler can be used as a library in two modes: `singleton` and `multi instance`. The multi instance version is for when you are using asynchronous compilations eg. in a webpack loader.\n\n```js\nconst fs = require('fs')\nconst dss = require('dss-compiler')\n\nconst src = `\n  .btn {\n    color: red\n  }\n`\n\ndss.singleton(src).then({ locals, css, flush } => {\n  fs.writeFileSync('./component1/styles.css.json', , JSON.stringify(locals))\n  fs.writeFileSync('./bundle.css', flush())\n})\n```\n\nFor more details see the [atomic-css](/atomic-css) page.\n\n## dss-classnames\n\nThis package implements the _classnames helper_ required to consume the DSS styles. Right now it contains only a JavaScript implementation, however we are planning to add implementations in other languages and always welcome user contributions! If you want to implement this helper in another language you can find more details on the [classnames helper page](/classnames-helper).\n\n\n```\nnpm i dss-classnames\n```\nWhich you can use similarly to the popular [classnames](https://www.npmjs.com/package/classnames) library:\n\n```js\nimport classNames from 'dss-classnames'\nimport styles from './component1/styles.css'\n\n\nconst test =\n`<div class=\"${classNames(styles.btn, styles.anotherClass, 'a-custom-class')}\">\n  hi\n</div>`\n```\n\nThis helper accepts a mix of DSS tokens and regular CSS classnames and makes sure that styles are resolved deterministically. It accepts a list of comma separated classes and you can even have conditions.\n\n```js\nclassNames(styles.btn, isDisabled && styles.btnDisabled)\n```\n\nWhen using DSS with React you might want to pair this helper with [`babel-plugin-classnames`](https://www.npmjs.com/package/babel-plugin-classnames) which imports `classNames` for you automatically and lets you write this instead:\n\n```js\nimport styles from './component1/styles.css'\n\n<div className={[styles.btn, styles.anotherClass, 'a-custom-class']}>hi</div>\n```\n\n## dss-webpack\n\nDSS comes with a webpack loader and plugin and since it works similarly to CSS Modules can leverage existing tools like `extract-text-webpack-plugin` (webpack 3) and `mini-css-extract-plugin` (webpack 4) to allow you to easily compile your styles.\n\nFor more details see the dedicated [webpack page](/webpack).\n\n## dss-next\n\nIf you use [Next.js](https://nextjs.org) we prepared a simple plugin for you to seamlessly integrate DSS.\n\n```\nnpm i dss-next\n```\n\nIn `next.config.js`\n\n```js\nconst withDSS = require('dss-next-dss')\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\n\nmodule.exports = withDSS({\n  dssLoaderOptions: {\n    localIdentName,\n    filename: 'static/index.css'\n  }\n})\n```\n\nYou will then need to add a `link` to `/_next/static/index.css` in `pages/_document.js`\n\n```js\n<link rel=\"stylesheet\" href=\"/_next/static/index.css\" />\n```\n"
  },
  {
    "path": "website/md/webpack.md",
    "content": "# webpack 📦\n\nDSS comes with a webpack loader and plugin and since it works similarly to CSS Modules can leverage existing tools like `extract-text-webpack-plugin` (webpack 3) and `mini-css-extract-plugin` (webpack 4) to allow you to easily compile your styles.\n\n```\nnpm i --save-dev dss-webpack\n```\n\n`dss-webpack` exports a plugin which optimizes your final bundle after extraction, and a loader that compiles your styles.\n\n## webpack 3\n\nFor webpack 3 you might want to use `extract-text-webpack-plugin`\n\n```js\nconst path = require('path')\nconst HtmlwebpackPlugin = require('html-webpack-plugin')\nconst ExtractTextPlugin = require('extract-text-webpack-plugin')\nconst DSSwebpackPlugin = require('dss-webpack')\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\n\nconst config = {\n  entry: path.resolve('./src/index.js'),\n  output: {\n    path: path.resolve('./dist'),\n    filename: '[name].js',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/,\n        use: ExtractTextPlugin.extract({\n          use: [\n            // This plugin is similar to the css-loader for CSS Modules\n            {\n              loader: DSSwebpackPlugin.loader,\n              query: {\n                // optional, adds readable classnames\n                localIdentName,\n              },\n            },\n          ],\n        }),\n      },\n    ],\n  },\n  plugins: [\n    new HtmlwebpackPlugin({\n      template: path.resolve('./src/index.html'),\n    }),\n    new ExtractTextPlugin('index.css'),\n\n    // Important! Optimizes your DSS styles - always include this.\n    new DSSwebpackPlugin({\n      test: /index\\.css$/,\n    }),\n  ],\n}\n\nmodule.exports = config\n```\n\n## webpack 4\n\nFor webpack 4 you might want to use `mini-css-extract-plugin`\n\n```js\nconst path = require('path')\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin')\nconst HtmlwebpackPlugin = require('html-webpack-plugin')\nconst DSSwebpackPlugin = require('dss-webpack')\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\nconst mode = process.env.NODE_ENV || 'development'\n\nconst config = {\n  mode,\n  entry: path.resolve('./src/index.js'),\n  output: {\n    path: path.resolve('./dist'),\n    filename: '[name].js',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/,\n        use: [\n          MiniCssExtractPlugin.loader,\n          {\n            // This plugin is similar to the css-loader for CSS Modules\n            loader: DSSwebpackPlugin.loader,\n            query: {\n              // optional, adds readable classnames\n              localIdentName,\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new HtmlwebpackPlugin({\n      template: path.resolve('./src/index.html'),\n    }),\n    new MiniCssExtractPlugin({\n      filename: 'index.css',\n    }),\n\n    // Important! Optimizes your DSS styles - always include this.\n    new DSSwebpackPlugin({\n      test: /index\\.css$/,\n    }),\n  ],\n}\n\nmodule.exports = config\n```\n\n## with SASS\n\nThe webpack configuration looks exactly the same as the previous ones except that now we test for `scss` files and run the `sass-loader` before the dss loader.\n\n```js\nrules: [\n  {\n    test: /\\.scss$/,\n    use: [\n      MiniCssExtractPlugin.loader,\n      {\n        // This plugin is similar to the css-loader for CSS Modules\n        loader: DSSwebpackPlugin.loader,\n        query: {\n          // optional, adds readable classnames\n          localIdentName,\n        },\n      },\n\n      // Compile sass before using DSSwebpackPlugin.loader\n      {\n        loader: 'sass-loader',\n        options: {\n          sourceMaps: false,\n        },\n      }\n\n    ],\n  },\n]\n```\n\n## with PostCSS\n\nThe webpack configuration looks exactly the same as the previous ones except that now we run the `postcss-loader` before the dss loader.\n\n```js\nrules: [\n  {\n    test: /\\.css$/,\n    use: [\n      MiniCssExtractPlugin.loader,\n      {\n        // This plugin is similar to the css-loader for CSS Modules\n        loader: DSSwebpackPlugin.loader,\n        query: {\n          // optional, adds readable classnames\n          localIdentName,\n        },\n      },\n\n      // Compile the CSS with PostCSS\n      {\n        loader: 'postcss-loader',\n        options: {\n          // Configure here the plugins or\n          // omit this option if you have a `postcss.config.js` file\n          plugins: () => [\n            require('postcss-easy-import')(),\n            require('postcss-simple-vars')({ variables: () => require('./theme') })\n            // ...\n          ],\n        },\n      }\n\n    ],\n  },\n]\n```\n"
  },
  {
    "path": "website/next.config.js",
    "content": "const withDSS = require('next-dss')\nconst withMDX = require('@zeit/next-mdx')({\n  extension: /\\.mdx?$/\n})\n\nconst localIdentName =\n  process.env.NODE_ENV === 'production' ? 'DSS-[hash:base32]' : '[name]-[local]--[hash:base32:5]'\n\nmodule.exports = withMDX(\n  withDSS({\n    dssLoaderOptions: {\n      localIdentName,\n      filename: 'static/index.css'\n    }\n  })\n)\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.1.0-beta.0\",\n  \"description\": \"\",\n  \"scripts\": {\n    \"dev\": \"next\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"export\": \"next build && next export\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@mdx-js/mdx\": \"^0.8.0\",\n    \"@zeit/next-mdx\": \"^1.1.0\",\n    \"dss-classnames\": \"0.1.0-beta.0\",\n    \"next\": \"^6.0.0\",\n    \"next-dss\": \"0.1.0-beta.0\",\n    \"postcss-easy-import\": \"^3.0.0\",\n    \"postcss-loader\": \"^2.1.5\",\n    \"postcss-simple-vars\": \"^4.1.0\",\n    \"react\": \"^16.3.2\",\n    \"react-dom\": \"^16.3.2\",\n    \"react-ga\": \"^2.5.3\",\n    \"system-font-css\": \"^2.0.2\"\n  },\n  \"devDependencies\": {\n    \"babel-plugin-classnames\": \"^0.1.0\"\n  }\n}\n"
  },
  {
    "path": "website/pages/_app.js",
    "content": "import DefaultApp, { Container } from 'next/app'\nimport Layout from '../components/layout'\nimport components from '../components/markdown'\nimport Analytics from '../components/analytics'\nimport CurrentPath from '../components/navigation/CurrentPath'\n\nexport default class App extends DefaultApp {\n  static async getInitialProps({ Component, router, ctx }) {\n    let pageProps = {}\n\n    if (Component.getInitialProps) {\n      pageProps = await Component.getInitialProps(ctx)\n    }\n\n    return { pageProps }\n  }\n\n  compomentDidMount() {}\n\n  render() {\n    const {\n      Component,\n      pageProps,\n      router: { route },\n    } = this.props\n    const meta = Component.meta || {}\n\n    return (\n      <Analytics id=\"UA-9670480-10\" route={route}>\n        <Container>\n          <CurrentPath.Provider value={route}>\n            <Layout title={meta.title}>\n              <Component {...pageProps} components={components} />\n            </Layout>\n          </CurrentPath.Provider>\n        </Container>\n      </Analytics>\n    )\n  }\n}\n"
  },
  {
    "path": "website/pages/_document.js",
    "content": "import Document, { Head, Main, NextScript } from 'next/document'\nimport Body from '../components/body'\n\nexport default class MyDocument extends Document {\n  render() {\n    return (\n      <html>\n        <Head>\n          <meta charset=\"utf-8\" />\n          <title>Deterministic Style Sheets</title>\n\n          <style>{`* { box-sizing: border-box; }`}</style>\n          <link rel=\"stylesheet\" href=\"/_next/static/index.css\" />\n          <link rel=\"icon\" href=\"/static/favicon.ico\" type=\"image/x-icon\" />\n\n          <meta\n            name=\"description\"\n            content=\"DSS is like CSS Modules but styles are compiled to atomic CSS classes which thanks to a helper resolve deterministically.\"\n          />\n          <meta name=\"image\" content=\"/static/dss.png\" />\n\n          <meta itemprop=\"name\" content=\"Deterministic Style Sheets\" />\n          <meta\n            itemprop=\"description\"\n            content=\"DSS is like CSS Modules but styles are compiled to atomic CSS classes which thanks to a helper resolve deterministically.\"\n          />\n          <meta itemprop=\"image\" content=\"/static/dss.png\" />\n\n          <meta name=\"twitter:card\" content=\"summary\" />\n          <meta name=\"twitter:title\" content=\"Deterministic Style Sheets\" />\n          <meta\n            name=\"twitter:description\"\n            content=\"DSS is like CSS Modules but styles are compiled to atomic CSS classes which thanks to a helper resolve deterministically.\"\n          />\n          <meta name=\"twitter:site\" content=\"@giuseppegurgone\" />\n          <meta name=\"twitter:image:src\" content=\"/static/dss.png\" />\n\n          <meta name=\"og:title\" content=\"Deterministic Style Sheets\" />\n          <meta\n            name=\"og:description\"\n            content=\"DSS is like CSS Modules but styles are compiled to atomic CSS classes which thanks to a helper resolve deterministically.\"\n          />\n          <meta name=\"og:image\" content=\"/static/dss.png\" />\n          <meta name=\"og:site_name\" content=\"Deterministic Style Sheets\" />\n          <meta name=\"og:locale\" content=\"en_US\" />\n          <meta name=\"og:type\" content=\"website\" />\n        </Head>\n        <Body>\n          <Main />\n          <NextScript />\n        </Body>\n      </html>\n    )\n  }\n}\n"
  },
  {
    "path": "website/pages/atomic-css.js",
    "content": "import Document from '../md/atomic-css.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/classnames-helper.js",
    "content": "import Document from '../md/classnames-helper.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/examples.js",
    "content": "import Document from '../md/examples.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/how-it-works.js",
    "content": "import Document from '../md/how-it-works.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/index.js",
    "content": "import Document from '../md/index.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/sass-preprocessors.js",
    "content": "import Document from '../md/sass-preprocessors.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/supported-css-features.js",
    "content": "import Document from '../md/supported-css-features.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/usage.js",
    "content": "import Document from '../md/usage.md'\nexport default Document\n"
  },
  {
    "path": "website/pages/webpack.js",
    "content": "import Document from '../md/webpack.md'\nexport default Document\n"
  },
  {
    "path": "website/postcss.config.js",
    "content": "module.exports = {\n  plugins: [\n    require('postcss-easy-import')(),\n    require('postcss-simple-vars')({ variables: () => require('./theme') })\n  ],\n  sourceMap: false\n}\n"
  },
  {
    "path": "website/static/playground/index.html",
    "content": "<!DOCTYPE html>\n<meta charSet=\"utf-8\" />\n<title>DSS Playground</title>\n<style>\n* { box-sizing: border-box; }\nbody { margin: 0; font-family: monospace; }\n.Playground {\n  display: flex;\n  flex-direction: column;\n  min-height: 100vh\n}\n.Playground-editors {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n}\n\n.Playground-editor {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  color: #1e3e83;\n  background-color: #eff4ff;\n  padding: 1em;\n  padding-top: 2.4em;\n  border-radius: 4px;\n  margin-top: 1em;\n  position: relative;\n}\n\n.Playground-editor textarea {\n  all: inherit;\n  border: 0;\n  padding: 0;\n  width: 100%;\n  flex: 1;\n}\n\n.Playground-result:before,\n.Playground-editor[data-lang]:before {\n  content: attr(data-lang);\n  position: absolute;\n  padding: 0.2em;\n  background-color: white;\n  top: 0;\n  left: 1em;\n}\n\n.Playground-editor[data-lang=\"js\"] textarea {\n  margin-top: 1em;\n}\n\n.Playground-result {\n  position: relative;\n  margin-top: 1em;\n  padding-top: 1.4em\n}\n\n.Playground-result:before {\n  background-color: #eff4ff;\n}\n\n.Playground-result iframe {\n  border: 0;\n  display: block;\n  width: 100%;\n  background-color: white;\n}\n\n.Playground-run {\n  border: 0;\n  display: block;\n  width: 100%;\n  color: white;\n  background-color: #3467d6;\n  padding: 0.5em;\n  text-transform: uppercase;\n  border-radius: 4px;\n}\n\n@media (min-width: 840px) {\n  .Playground {\n    flex-direction: row;\n  }\n  .Playground-result {\n    margin-top: 2.8em;\n    flex: 1;\n  }\n}\n</style>\n\n<div class=\"Playground\">\n  <div class=\"Playground-editors\">\n    <button class=\"Playground-run\">run</button>\n    <div class=\"Playground-editor\" data-lang=\"css\">\n<textarea>\n.red { color: red }\n.green { color: green }\n</textarea>\n    </div>\n    <div class=\"Playground-editor\" data-lang=\"js\">\n      <div class=\"FakeImport\">import classnames from 'dss-classnames'</div>\n      <div class=\"FakeImport\">import styles from './styles.css'</div>\n<textarea>\n// try to invert the order of the classes!\n\ndocument.body.innerHTML = `\n<div class=\"${classnames(styles.red, styles.green)}\">Hello from DSS!</div>\n<div class=\"${classnames(styles.green, styles.red)}\">Hello from DSS!</div>\n`\n</textarea>\n    </div>\n  </div>\n  <div class=\"Playground-result\" data-lang=\"result\">\n  </div>\n</div>\n\n<script>\n  (function () {\n    const cssEditor = document.querySelector('.Playground-editor[data-lang=\"css\"] textarea')\n    const jsEditor = document.querySelector('.Playground-editor[data-lang=\"js\"] textarea')\n    const result = document.querySelector('.Playground-result')\n    document.querySelector('.Playground-run').addEventListener('click', run)\n\n    function run() {\n      const resultIframe = document.createElement('iframe')\n      result.innerHTML = ''\n      result.appendChild(resultIframe)\n\n      getCSS()\n        .then(dss => {\n          const resultDocument = resultIframe.contentDocument\n          resultDocument.open()\n          resultDocument.write(\n            getHTML(getJS(), dss)\n          )\n          resultDocument.close()\n        })\n    }\n    run()\n\n    function getHTML(js, dss) {\n      console.log(dss)\n      return `\n        <!doctype html>\n        <script src=\"https://unpkg.com/dss-classnames@0.1.0-beta.0/index.js\"><\\/script>\n        <style>${dss.css}</style>\n        <script>\n          window.addEventListener('load', function () {\n            ${dss.error\n              ? `document.body.innerHTML = '<div class=\"error\">Error: ${JSON.stringify(dss.error)}</div>'`\n              : `(new Function(${JSON.stringify(`const styles = ${JSON.stringify(dss.locals)};` + js)})())`\n            }\n          })\n        <\\/script>\n      `\n    }\n    function getJS() {\n      return jsEditor.value\n    }\n    function getCSS() {\n      const src = cssEditor.value.trim()\n      if (!src) {\n        return Promise.resolve({\n          css: '',\n          locals: {},\n          error: 'Your CSS is an empty string.'\n        })\n      }\n      return fetch('https://IncompatibleNarrowProgrammers.gsppe.repl.co', {\n        method: 'post',\n        body: src,\n      }).then(r => {\n        if (r.status !== 200 && r.status !== 304) {\n          return Promise.reject(\n            `An error occurred while processing your styles. ${r.status} ${r.statusText}`\n          )\n        }\n        return r.json()\n      }).catch(e => {\n        return {\n          css: '',\n          locals: {},\n          error: e.message,\n        }\n      })\n    }\n  }())\n</script>\n"
  },
  {
    "path": "website/theme/index.js",
    "content": "const { generateVariables } = require('./utils')\nconst { borderRadius, color, fontFamily, fontSize, spacing } = require('./variables')\n\nconst theme = {\n  Logo: {\n    Color: color.White,\n    Background: color.Blue,\n    Size: fontSize[0],\n  },\n  Heading: {\n    Color: color.Blue,\n    FontSize: fontSize[3],\n    FontFamily: fontFamily.Base,\n    FontWeight: 'normal',\n  },\n  Link: {\n    Color: color.Blue,\n    StateColor: color.Blue1,\n    FontSize: fontSize[3],\n    FontFamily: fontFamily.Base,\n  },\n  NavigationButton: {\n    Color: color.Blue,\n    StateColor: color.Blue1,\n    BorderRadius: borderRadius[5],\n    Size: fontSize[1],\n  },\n  SideBar: {\n    BackgroundColor: color.Gray,\n    StateBackgroundColor: color.Gray3,\n    Color: color.Blue1,\n    Spacing: spacing[1],\n    // LogoSize - NavigationButtonSize\n    NavigationSpacing: fontSize[0] - fontSize[1],\n  },\n  Main: {\n    BackgroundColor: color.Gray,\n    ContentBackgroundColor: color.White,\n    Color: color.Blue1,\n    Spacing: spacing[0],\n  },\n  MarkdownP: {\n    FontSize: fontSize[3],\n    FontFamily: fontFamily.Base,\n  },\n  MarkdownCode: {\n    FontSize: fontSize[3] - borderRadius[4] / 2,\n    FontFamily: fontFamily.Monospace,\n    Color: color.Blue1,\n    BackgroundColor: color.Blue6,\n    Spacing: borderRadius[4],\n    BorderRadius: borderRadius[4],\n  },\n  MarkdownUL: {\n    FontSize: fontSize[3],\n    FontFamily: fontFamily.Base,\n    ListStyle: 'square',\n  },\n}\n\nexports = module.exports = Object.assign(\n  generateVariables(theme),\n  generateVariables({ borderRadius, color, fontFamily, fontSize, spacing }, 'u-')\n)\n"
  },
  {
    "path": "website/theme/utils.js",
    "content": "function fixNumber(thing) {\n  return typeof thing === 'number' ? thing + 'px' : thing\n}\n\nfunction generateVariables(variables, prefix = '') {\n  return Object.keys(variables).reduce((vars, prop) => {\n    const propVal = variables[prop]\n    if (Array.isArray(propVal)) {\n      propVal.forEach((val, index) => {\n        vars[`${prefix}${prop}${index + 1}`] = fixNumber(val)\n      })\n    } else {\n      Object.keys(propVal).forEach(subProp => {\n        // colorWhite1\n        vars[`${prefix}${prop}${subProp}`] = fixNumber(propVal[subProp])\n      })\n    }\n    return vars\n  }, {})\n}\n\nexports = module.exports = {\n  generateVariables,\n}\n"
  },
  {
    "path": "website/theme/variables.json",
    "content": "{\n  \"color\": {\n    \"White\": \"#fff\",\n    \"Gray\": \"#fafafa\",\n    \"Gray3\": \"#f4f4f4\",\n    \"Black\": \"#000\",\n    \"Black1\": \"#111\",\n    \"Black2\": \"#222\",\n    \"Blue\": \"#3467d6\",\n    \"Blue1\": \"#1e3e83\",\n    \"Blue2\": \"#2b57b6\",\n    \"Blue6\": \"#eff4ff\"\n  },\n  \"borderRadius\": [20, 16, 12, 6, 4, 2],\n  \"fontFamily\": {\n    \"Base\": \"system-ui, sans-serif\",\n    \"Serif\": \"serif\",\n    \"SansSerif\": \"sans-serif\",\n    \"Monospace\": \"Monaco, monospace\"\n  },\n  \"fontSize\": [36, 24, 18, 16, 14, 12],\n  \"spacing\": [36, 24, 18, 16, 14, 12]\n}\n"
  }
]