postcss-elm-tailwind
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -1,2 +0,2 @@ | ||
Nodeunit contributors (sorted alphabetically) | ||
postcss-elm-tailwind contributors (sorted alphabetically) | ||
============================================ | ||
@@ -6,9 +6,9 @@ | ||
* **[Nhan Thai](https://github.com/dandoh)** | ||
* **[Phill Sparks](https://github.com/sparksp)** | ||
* **[Steven Vandevelde](https://github.com/icidasset)** | ||
* **[Nhan Thai](https://github.com/dandoh)** | ||
**[Full contributors list](https://github.com/monty5811/postcss-elm-tailwind/graphs/contributors).** | ||
[Full contributors list](https://github.com/monty5811/postcss-elm-tailwind/graphs/contributors). |
142
helpers.js
@@ -1,8 +0,31 @@ | ||
function elmHeader(elmModuleName, elm_fns) { | ||
const s = new Set(elm_fns); | ||
let tmp = Array.from(s.values()); | ||
tmp.push("classList"); | ||
// code gen stuff | ||
function elmBodyHtml(elmModuleName, classes) { | ||
return elmHeaderHtml(elmModuleName, classes) + | ||
elmBody({ type: "Html.Attribute msg", fn: "A.class " }, classes); | ||
} | ||
function elmBodyString(elmModuleName, classes) { | ||
return elmHeaderString(elmModuleName, classes) + | ||
elmBody({ type: "String", fn: "" }, classes); | ||
} | ||
function elmBodySvg(elmModuleName, classes) { | ||
return elmHeaderSvg(elmModuleName, classes) + | ||
elmBody({ type: "Svg.Attribute msg", fn: "A.class " }, classes); | ||
} | ||
function elmHeaderExports(elmFns, includeClassList) { | ||
let tmp = Array.from(elmFns.values()); | ||
if (includeClassList) { | ||
tmp.push("classList"); | ||
} | ||
tmp.sort(); | ||
const l = tmp.join("\n , "); | ||
return tmp.join("\n , "); | ||
} | ||
function elmHeaderHtml(elmModuleName, elmFns) { | ||
l = elmHeaderExports(elmFns, true); | ||
return `module ${elmModuleName} exposing | ||
@@ -22,6 +45,32 @@ ( ${l} | ||
function elmBody(classes) { | ||
function elmHeaderSvg(elmModuleName, elmFns) { | ||
l = elmHeaderExports(elmFns, true); | ||
return `module ${elmModuleName} exposing | ||
( ${l} | ||
) | ||
import Svg | ||
import Svg.Attributes as A | ||
classList : List ( Svg.Attribute msg, Bool ) -> List (Svg.Attribute msg) | ||
classList classes = | ||
List.map Tuple.first <| List.filter Tuple.second classes | ||
`; | ||
} | ||
function elmHeaderString(elmModuleName, elmFns) { | ||
l = elmHeaderExports(elmFns, false); | ||
return `module ${elmModuleName} exposing | ||
( ${l} | ||
) | ||
`; | ||
} | ||
function elmBody(config, classes) { | ||
let body = ""; | ||
for (var fn of classes.values()) { | ||
body = body + fn; | ||
for (let [cls, elm] of classes) { | ||
body = body + elmFunction(config, { cls, elm }); | ||
} | ||
@@ -31,17 +80,12 @@ return body; | ||
function elmFunction(cls, elm) { | ||
function elmFunction(config, { cls, elm }) { | ||
return ` | ||
${elm} : Html.Attribute msg | ||
${elm} : ${config.type} | ||
${elm} = | ||
A.class "${cls}" | ||
${config.fn}"${cls}" | ||
`; | ||
} | ||
const defaultOpts = { | ||
elmFile: "src/TW.elm", | ||
elmModuleName: "TW", | ||
prefix: "", | ||
nameStyle: "snake" | ||
}; | ||
// parse, clean up stuff | ||
@@ -114,27 +158,53 @@ function fixClass(cls) { | ||
// options stuff | ||
const defaultOpts = { | ||
elmFile: "src/TW.elm", | ||
elmModuleName: "TW", | ||
prefix: "", | ||
nameStyle: "snake", | ||
formats: { | ||
/* | ||
string: { | ||
elmFile: "src/TW/String.elm", | ||
elmModuleName: "TW.String" | ||
}, | ||
svg: { | ||
elmFile: "src/TW/Svg.elm", | ||
elmModuleName: "TW.Svg", | ||
} | ||
*/ | ||
} | ||
}; | ||
function cleanOpts(opts) { | ||
if (opts === undefined) { | ||
opts = defaultOpts; | ||
} | ||
if (!opts.elmFile) { | ||
opts.elmFile = defaultOpts.elmFile; | ||
} | ||
if (!opts.prefix) { | ||
opts.prefix = defaultOpts.prefix; | ||
} | ||
if (!opts.elmModuleName) { | ||
opts.elmModuleName = defaultOpts.elmModuleName; | ||
} | ||
if (!opts.nameStyle) { | ||
opts.nameStyle = defaultOpts.nameStyle; | ||
} | ||
opts = { ...defaultOpts, ...opts }; | ||
opts.formats = { ...opts.formats }; | ||
return opts; | ||
} | ||
exports.elmHeader = elmHeader; | ||
exports.elmBody = elmBody; | ||
function formats(opts) { | ||
return [ | ||
cleanFormat(opts, elmBodyHtml), | ||
cleanFormat({ ...opts.formats.string }, elmBodyString), | ||
cleanFormat({ ...opts.formats.svg }, elmBodySvg) | ||
].filter(f => f); | ||
} | ||
function cleanFormat({ elmFile, elmModuleName }, elmBodyFn) { | ||
if (!elmFile) return false; | ||
if (!elmModuleName) return false; | ||
return { elmFile, elmModuleName, elmBodyFn }; | ||
} | ||
exports.cleanOpts = cleanOpts; | ||
exports.defaultOpts = defaultOpts; | ||
exports.elmBodyHtml = elmBodyHtml; | ||
exports.elmBodyString = elmBodyString; | ||
exports.elmBodySvg = elmBodySvg; | ||
exports.elmFunction = elmFunction; | ||
exports.fixClass = fixClass; | ||
exports.formats = formats; | ||
exports.toElmName = toElmName; | ||
exports.cleanOpts = cleanOpts; | ||
exports.defaultOpts = defaultOpts; |
49
index.js
const fs = require("fs"); | ||
const path = require("path"); | ||
let postcss = require("postcss"); | ||
const { promisify } = require("util"); | ||
const mkdir = promisify(fs.mkdir); | ||
let h = require("./helpers.js"); | ||
let classes = new Map(); | ||
let elm_fns = new Array(); | ||
@@ -14,24 +17,26 @@ module.exports = postcss.plugin("postcss-elm-tailwind", opts => { | ||
// Transform CSS AST here | ||
root.walkRules(rule => { | ||
rule.selector | ||
.split(" ") | ||
.map(sel => sel.split(",")) | ||
.reduce((arr, v) => (arr.push(...v), arr), []) | ||
.forEach(selector => processSelector(selector, opts)); | ||
root.walkRules(/^\./, rule => { | ||
rule.selectors.forEach(selector => processSelector(selector, opts)); | ||
}); | ||
const elmModule = h.elmHeader(opts.elmModuleName, elm_fns) + | ||
h.elmBody(classes); | ||
// writing to disk | ||
fs.writeFile(opts.elmFile, elmModule, err => { | ||
if (err) { | ||
return console.log(err); | ||
} | ||
console.log(opts.elmFile, "was saved!"); | ||
}); | ||
const formats = h | ||
.formats(opts) | ||
.map(({ elmFile, elmModuleName, elmBodyFn }) => | ||
writeFile(elmFile, elmBodyFn(elmModuleName, classes))); | ||
return tap(Promise.all(formats), p => | ||
p.then(files => console.log("Saved", files))); | ||
}; | ||
}); | ||
async function writeFile(fname, content) { | ||
folder = path.dirname(fname); | ||
await mkdir(folder, { recursive: true }); | ||
return new Promise((resolve, reject) => | ||
fs.writeFile(fname, content, err => { | ||
if (err) return reject(err); | ||
resolve(fname); | ||
})); | ||
} | ||
function processSelector(selector, opts) { | ||
@@ -48,4 +53,8 @@ if (!selector.startsWith(".")) { | ||
classes.set(cls, h.elmFunction(cls, elm)); | ||
elm_fns.push(elm); | ||
classes.set(cls, elm); | ||
} | ||
const tap = (v, fn) => { | ||
fn(v); | ||
return v; | ||
}; |
{ | ||
"name": "postcss-elm-tailwind", | ||
"main": "./index.js", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "PostCSS plugin Tailwind classes for Elm", | ||
@@ -19,3 +19,5 @@ "keywords": [ | ||
"repository": "monty5811/postcss-elm-tailwind", | ||
"dependencies": {}, | ||
"dependencies": { | ||
"postcss": "^7.0.18" | ||
}, | ||
"devDependencies": { | ||
@@ -28,8 +30,5 @@ "elm": "^0.19.1-2", | ||
}, | ||
"peerDependencies": { | ||
"postcss": "^7.0.18" | ||
}, | ||
"engines": { | ||
"node": ">=8.0.0" | ||
"node": ">=10.0.0" | ||
} | ||
} |
@@ -83,2 +83,48 @@ # postcss-elm-tailwind | ||
### Other output formats | ||
#### SVG | ||
If you want to use Tailwind classes to style `SVG` you can output an `Svg` module like this: | ||
```js | ||
module.exports = { | ||
plugins: [ | ||
require("tailwindcss"), | ||
require("postcss-elm-tailwind")({ | ||
elmFile: "src/Tailwind.elm", | ||
elmModule: "Tailwind", | ||
formats: { | ||
svg: { | ||
elmFile: "src/Tailwind/Svg.elm", | ||
elmModuleName: "Tailwind.Svg" | ||
} | ||
} | ||
}) | ||
] | ||
}; | ||
``` | ||
#### String | ||
If you want access to the class names themselves, you can output a `String` module as an escape hatch: | ||
```js | ||
module.exports = { | ||
plugins: [ | ||
require("tailwindcss"), | ||
require("postcss-elm-tailwind")({ | ||
elmFile: "src/Tailwind.elm", | ||
elmModule: "Tailwind", | ||
formats: { | ||
string: { | ||
elmFile: "src/Tailwind/String.elm", | ||
elmModuleName: "Tailwind.String" | ||
} | ||
} | ||
}) | ||
] | ||
}; | ||
``` | ||
## Other things to note | ||
@@ -85,0 +131,0 @@ |
@@ -10,3 +10,4 @@ const h = require("../helpers"); | ||
prefix: "", | ||
nameStyle: "snake" | ||
nameStyle: "snake", | ||
formats: {} | ||
}); | ||
@@ -19,3 +20,4 @@ }); | ||
prefix: "", | ||
nameStyle: "snake" | ||
nameStyle: "snake", | ||
formats: {} | ||
}); | ||
@@ -28,3 +30,4 @@ }); | ||
prefix: "tw--", | ||
nameStyle: "snake" | ||
nameStyle: "snake", | ||
formats: {} | ||
}); | ||
@@ -186,1 +189,33 @@ }); | ||
}); | ||
describe("elmFunction", () => { | ||
it("generates Html attributes", () => { | ||
assert.ok( | ||
/Html\.Attribute/.test( | ||
h.elmFunction( | ||
{ type: "Html.Attribute msg", fn: "A.class " }, | ||
"bg-pink-700", | ||
"bg_pink_700" | ||
) | ||
) | ||
); | ||
}); | ||
it("generates Svg attributes", () => { | ||
assert.ok( | ||
/Svg\.Attribute/.test( | ||
h.elmFunction( | ||
{ type: "Svg.Attribute msg", fn: "A.class " }, | ||
"bg-pink-700", | ||
"bg_pink_700" | ||
) | ||
) | ||
); | ||
}); | ||
it("generates strings", () => { | ||
assert.ok( | ||
/String/.test( | ||
h.elmFunction({ type: "String", fn: "" }, "bg-pink-700", "bg_pink_700") | ||
) | ||
); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
19501
434
135
+ Addedpostcss@^7.0.18