Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sheetify

Package Overview
Dependencies
Maintainers
3
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sheetify - npm Package Compare versions

Comparing version 4.1.2 to 5.0.0

test/fixtures/import-broken-source.js

37

index.js

@@ -7,2 +7,3 @@ const cssPrefix = require('postcss-prefix')

const crypto = require('crypto')
const xtend = require('xtend')

@@ -13,3 +14,3 @@ module.exports = sheetify

// (str, str, obj?, fn) -> str
function sheetify (src, filename, options, push) {
function sheetify (src, filename, options, done) {
// handle tagged template calls directly from Node

@@ -25,3 +26,3 @@ if (Array.isArray(src)) src = src.join('')

// only parse if in a browserify transform
if (filename) parseCss(src, filename, prefix, options, push)
if (filename) parseCss(src, filename, prefix, options, done)

@@ -33,19 +34,14 @@ return prefix

// (str, str, str, obj, fn) -> null
function parseCss (src, filename, prefix, options, next) {
function parseCss (src, filename, prefix, options, done) {
assert.equal(typeof filename, 'string', 'filename must be a string')
assert.equal(typeof prefix, 'string', 'prefix must be a string')
assert.equal(typeof options, 'object', 'options must be a object')
assert.equal(typeof next, 'function', 'done must be a function')
assert.equal(typeof done, 'function', 'done must be a function')
var p = postcss()
if (options.global !== true) p = p.use(cssPrefix('.' + prefix))
const processedCss = p
.process(src.toString())
.toString()
next(function (done) {
applyTransforms(filename, processedCss, options, function (err, css) {
return done(err, css, prefix)
})
applyTransforms(filename, String(src), xtend(options), function (err, css) {
if (err) return done(err)
var p = postcss()
if (options.global !== true) p = p.use(cssPrefix('.' + prefix))
css = p.process(css).toString()
return done(null, css, prefix)
})

@@ -57,7 +53,4 @@

function applyTransforms (filename, src, options, done) {
options.u = options.u || []
options.use = options.use || []
var use = [].concat(options.use).concat(options.u)
mapLimit(use, 1, iterate, function (err) {
options.use = [].concat(options.use || []).concat(options.u || [])
mapLimit(options.use, 1, iterate, function (err) {
if (err) return done(err)

@@ -79,3 +72,5 @@ done(null, src)

const resolveOpts = { basedir: opts.basedir || options.basedir }
const resolveOpts = {
basedir: opts.basedir || options.basedir || process.cwd()
}
nodeResolve(name, resolveOpts, function (err, transformPath) {

@@ -82,0 +77,0 @@ if (err) return done(err)

{
"name": "sheetify",
"version": "4.1.2",
"version": "5.0.0",
"description": "Modular CSS bundler",

@@ -9,4 +9,4 @@ "repository": "sheetify/sheetify",

"deps": "dependency-check . --entry transform.js . && dependency-check . --entry transform.js --extra --no-dev -i insert-css",
"test": "standard && npm run deps && tape test/*",
"test:cov": "standard && npm run deps && NODE_ENV=test istanbul cover test/coverage.js",
"test": "standard && npm run deps && tape test/index.js",
"test:cov": "standard && npm run deps && NODE_ENV=test istanbul cover test/index.js",
"format": "standard --format"

@@ -25,10 +25,9 @@ },

"dependencies": {
"end-of-stream": "^1.1.0",
"falafel": "^1.2.0",
"is-stream": "^1.0.1",
"map-limit": "0.0.1",
"mkdirp": "^0.5.1",
"postcss": "^5.0.10",
"postcss-prefix": "^1.0.3",
"resolve": "^1.1.7",
"static-eval": "^0.2.4",
"style-resolve": "^1.0.0",

@@ -44,4 +43,6 @@ "through2": "^2.0.0",

"concat-stream": "^1.5.1",
"css-extract": "^1.0.0",
"css-type-base": "^1.0.2",
"dependency-check": "^2.5.1",
"insert-css": "^0.2.0",
"istanbul": "^0.3.19",

@@ -48,0 +49,0 @@ "jsdom": "^8.0.2",

# sheetify
<img
alt="sheetify logo"
height="100"
style="max-width: 100%"
data-canonical-src="https://github.com/sheetify/logo"
src="https://raw.githubusercontent.com/sheetify/logo/master/512v6.png">
[![NPM version][npm-image]][npm-url]

@@ -138,23 +131,12 @@ [![build status][travis-image]][travis-url]

To write the compiled CSS to a separate file, rather than keep it in the
bundle:
bundle use [css-extract][2]:
```sh
$ browserify -t [ sheetify/transform -o bundle.css ] index.js > bundle.js
$ browserify index.js \
-t [ sheetify/transform ] \
-p [ css-extract -o bundle.css ] index.js \
-o bundle.js
```
[css-extract][2] can also write to a stream from the JS api, look at the
documentation to see how.
## Write to stream
To write the compiled CSS to a stream:
```js
const browserify = require('browserify')
const fs = require('fs')
const b = browserify(path.join(__dirname, 'transform/source.js'))
const ws = fs.createWriteStream('/bundle.css')
b.transform('sheetify', { out: ws })
const r = b.bundle().pipe(fs.createWriteStream('./bundle.js'))
r.on('end', () => ws.end())
```
Browserify transforms don't know when `browserify` is done, so we have to
attach a listener on browserify for the `'end'` event to close the writeStream
accordingly.
## Plugins

@@ -207,4 +189,5 @@ Sheetify uses [plugins](#plugins) that take CSS and apply a transform.

```sh
$ browserify -t [ sheetify/transform -o bundle.css ] index.js > bundle.js
$ browserify -t [ sheetify/transform -u sheetify-cssnext ] index.js > bundle.js
```
Or the equivalent options by passing in a configuration object in the

@@ -216,9 +199,9 @@ JavaScript API:

const b = browserify(path.join(__dirname, 'transform/source.js'))
b.transform('sheetify', { out: path.join(__dirname, '/bundle.css') })
b.transform('sheetify', { use: [ 'sheetify-cssnext' ] })
b.bundle().pipe(process.stdout)
```
The following options are available:
```txt
Options:
-o, --out Specify an output file
-u, --use Consume a sheetify plugin

@@ -248,2 +231,3 @@ ```

JS, CSS and HTML
- [css-extract][2]: extract CSS from a browserify bundle

@@ -255,6 +239,6 @@ ## License

[npm-url]: https://npmjs.org/package/sheetify
[travis-image]: https://img.shields.io/travis/sheetify/sheetify/master.svg?style=flat-square
[travis-url]: https://travis-ci.org/sheetify/sheetify
[codecov-image]: https://img.shields.io/codecov/c/github/sheetify/sheetify/master.svg?style=flat-square
[codecov-url]: https://codecov.io/github/sheetify/sheetify
[travis-image]: https://img.shields.io/travis/stackcss/sheetify/master.svg?style=flat-square
[travis-url]: https://travis-ci.org/stackcss/sheetify
[codecov-image]: https://img.shields.io/codecov/c/github/stackcss/sheetify/master.svg?style=flat-square
[codecov-url]: https://codecov.io/github/stackcss/sheetify
[downloads-image]: http://img.shields.io/npm/dm/sheetify.svg?style=flat-square

@@ -265,1 +249,2 @@ [downloads-url]: https://npmjs.org/package/sheetify

[1]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/#toc-style-host
[2]: https://github.com/stackcss/css-extract

@@ -9,52 +9,40 @@ const browserify = require('browserify')

test('import', function (t) {
t.plan(1)
test('npm import', function (t) {
t.test('should import npm packages', function (t) {
t.plan(1)
const expath = require.resolve('css-type-base/index.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const expath = require.resolve('css-type-base/index.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'package was imported')
})
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'package was imported')
})
const bOpts = { browserField: false }
const b = browserify(path.join(__dirname, 'import/source.js'), bOpts)
b.transform(sheetify, {
basedir: path.join(__dirname, 'plugins'),
o: ws
})
const bOpts = { browserField: false }
const bpath = path.join(__dirname, 'fixtures/import-source.js')
browserify(bpath, bOpts)
.transform(sheetify)
.plugin('css-extract', { out: outFn })
.bundle()
const r = b.bundle()
r.resume()
r.on('end', function () {
ws.end()
function outFn () {
return ws
}
})
})
test('broken import should emit an error', function (t) {
t.plan(1)
t.test('should emit an error on broken import', function (t) {
t.plan(1)
const inpath = path.join(__dirname, 'import/broken.js')
const inpath = path.join(__dirname, 'fixtures/import-broken-source.js')
const bOpts = { browserField: false }
const b = browserify(inpath, bOpts)
b.transform(sheetify)
const ws = concat(function (buf) {
const res = String(buf).trim()
console.log(res)
const r = b.bundle()
r.resume()
r.on('error', function (e) {
t.ok(/Cannot find module/.test(e), 'emits an error')
})
})
const bOpts = { browserField: false }
const b = browserify(inpath, bOpts)
b.transform(sheetify, {
basedir: path.join(__dirname, 'plugins'),
o: ws
})
const r = b.bundle()
r.resume()
r.on('error', function (e) {
t.ok(/cannot be imported/.test(e), 'emits an error')
})
r.on('end', function () {
ws.end()
})
})

@@ -8,26 +8,28 @@ const browserify = require('browserify')

const sheetify = require(path.join(__dirname, '../transform'))
const expath = path.join(__dirname, 'plugins/expected.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
test('plugins', function (t) {
t.plan(1)
t.test('should transform CSS', function (t) {
t.plan(1)
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'css is transformed')
})
const expath = path.join(__dirname, 'fixtures/plugins-expected.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const bOpts = { browserField: false }
const b = browserify(path.join(__dirname, 'plugins/source.js'), bOpts)
b.transform(sheetify, {
use: [ [ 'sheetify-cssnext', { sourcemap: false } ] ],
basedir: path.join(__dirname, 'plugins'),
o: ws
})
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'CSS was transformed')
})
const r = b.bundle()
r.resume()
r.on('end', function () {
ws.end()
const bOpts = { browserField: false }
const bpath = path.join(__dirname, 'fixtures/plugins-source.js')
browserify(bpath, bOpts)
.transform(sheetify, {
use: [ [ 'sheetify-cssnext', { sourcemap: false } ] ]
})
.plugin('css-extract', { out: outFn })
.bundle()
function outFn () {
return ws
}
})
})

@@ -6,27 +6,102 @@ const browserify = require('browserify')

const fs = require('fs')
const vm = require('vm')
const sheetify = require(path.join(__dirname, '../transform'))
const transform = require('../transform')
const sheetify = require('..')
test('test global prefix', function (t) {
t.plan(1)
test('prefix', function (t) {
t.test('should return a prefix when called in Node', function (t) {
t.plan(1)
const prefix = sheetify('.foo { color: blue; }')
t.equal(prefix, '_d1b3f246', 'prefix is equal')
})
const ws = concat(function (buf) {
const result = String(buf).trim()
const expectpath = path.join(__dirname, 'prefix/source.css')
const expected = fs.readFileSync(expectpath, 'utf8').trim()
t.equal(result, expected, 'exorcised to stream')
t.test('should prefix and inline template strings', function (t) {
t.plan(3)
const expath = path.join(__dirname, 'fixtures/prefix-inline-expected.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'css is equal')
})
const bOpts = { browserField: false }
const bpath = path.join(__dirname, 'fixtures/prefix-inline-source.js')
browserify(bpath, bOpts)
.transform(transform)
.plugin('css-extract', { out: outFn })
.bundle(parseBundle)
function outFn () {
return ws
}
function parseBundle (err, src) {
t.ifError(err, 'no error')
const c = { console: { log: log } }
vm.runInNewContext(src.toString(), c)
function log (msg) {
t.equal(msg, '_0081131d', 'echoes prefix')
}
}
})
const bOpts = { browserField: false }
const b = browserify(path.join(__dirname, 'prefix/global-true.js'), bOpts)
b.transform(sheetify, {
basedir: path.join(__dirname, 'prefix'),
o: ws
t.test('should prefix and inline imported files', function (t) {
t.plan(3)
const expath = path.join(__dirname, 'fixtures/prefix-import-expected.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'css is equal')
})
const bOpts = { browserField: false }
const bpath = path.join(__dirname, 'fixtures/prefix-import-source.js')
browserify(bpath, bOpts)
.transform(transform)
.plugin('css-extract', { out: outFn })
.bundle(parseBundle)
function outFn () {
return ws
}
function parseBundle (err, src) {
t.ifError(err, 'no error')
const c = { console: { log: log } }
vm.runInNewContext(src.toString(), c)
function log (msg) {
t.equal(msg, '_c284eb7d', 'echoes prefix')
}
}
})
const r = b.bundle()
r.resume()
r.on('end', function () {
ws.end()
t.test('should disable prefixing when global:true', function (t) {
t.plan(1)
const expath = path.join(__dirname, 'fixtures/prefix-global-expected.css')
const expected = fs.readFileSync(expath, 'utf8').trim()
const ws = concat(function (buf) {
const res = String(buf).trim()
t.equal(res, expected, 'css is equal')
})
const bOpts = { browserField: false }
const bpath = path.join(__dirname, 'fixtures/prefix-global-source.js')
browserify(bpath, bOpts)
.transform(transform)
.plugin('css-extract', { out: outFn })
.bundle()
function outFn () {
return ws
}
})
})
const cssResolve = require('style-resolve').sync
const staticEval = require('static-eval')
const mapLimit = require('map-limit')
const isStream = require('is-stream')
const eos = require('end-of-stream')
const through = require('through2')
const falafel = require('falafel')
const assert = require('assert')
const mkdirp = require('mkdirp')
const xtend = require('xtend')

@@ -18,19 +17,14 @@ const path = require('path')

// inline sheetify transform for browserify
// 1. walk AST
// 2. replace sheetify references with prefix id's
// 3. aggregate all transform calls
// 3. asynchronously either replace sheetify calls
// with CSS injection or extract CSS to callback
// 4. flush transform
// obj -> (str, opts) -> str
function transform (filename, options) {
const bufs = []
const nodes = []
var mname = null
const opts = xtend(options || {
basedir: process.cwd(),
use: [],
out: ''
})
const opts = xtend(options || {})
opts.basedir = opts.basedir || process.cwd()
if (opts.o) opts.out = opts.o
opts.use = [].concat(opts.use || []).concat(opts.u || [])
// argv parsing
if (opts.o) opts.out = opts.o
if (opts.out) {

@@ -41,2 +35,3 @@ if (typeof opts.out === 'string') opts.out = path.resolve(opts.out)

const bufs = []
const transformStream = through(write, end)

@@ -56,4 +51,11 @@ return transformStream

const self = this
// cool, you've made it this far. We know this is gross,
// but tough times call for tough measure. Please don't
// judge us too harshly, we'll work on perf ✨soon✨ -yw
const nodes = []
var mname = null
const src = Buffer.concat(bufs).toString('utf8')
const ast = falafel(src, { ecmaVersion: 6 }, walk)
const tmpAst = falafel(src, { ecmaVersion: 6 }, identifyModuleName)
const ast = falafel(tmpAst.toString(), { ecmaVersion: 6 }, extractNodes)

@@ -68,117 +70,91 @@ // transform all detected nodes and

// find sheetify call
// - read from file, read from inline or resolve npm package
// - detect if should be prefixed or not
function iterate (args, done) {
const transformFn = args[0]
const node = args[1]
transformFn(function (err, css, prefix) {
if (err) return done(err)
if (opts.out) {
// exorcise to external file
if (typeof opts.out === 'string') {
const dirname = path.dirname(opts.out)
mkdirp(dirname, function (err) {
if (err) return done(err)
const ws = fs.createWriteStream(opts.out)
eos(ws, done)
node.update('"' + prefix + '"')
ws.end(css)
})
} else {
// exorcise to stream
const ws = opts.out
node.update('"' + prefix + '"')
ws.emit('file', filename)
ws.write(css)
done()
}
} else {
// inject CSS inline
const str = [
"((require('insert-css')(" + JSON.stringify(css) + ')',
' || true) && ' + JSON.stringify(prefix) + ')'
].join('')
node.update(str)
done()
}
})
function identifyModuleName (node) {
if (mname) return
if (node.type === 'CallExpression' &&
node.callee && node.callee.name === 'require' &&
node.arguments.length === 1 &&
node.arguments[0].value === 'sheetify') {
node.update('0')
mname = node.parent.id.name
}
}
}
// transform an AST node
// obj -> null
function walk (node) {
opts.global = false
// transform require calls
if (node.type === 'CallExpression' &&
node.callee && node.callee.name === 'require' &&
node.arguments.length === 1 &&
node.arguments[0].value === 'sheetify') {
node.update('0')
mname = node.parent.id.name
return
function extractNodes (node) {
extractTemplateNodes(node)
extractImportNodes(node)
}
// transform template strings
// modify node value to prefix, and push css for transform
if (node.type === 'TemplateLiteral' &&
node.parent && node.parent.tag &&
node.parent.tag.name === mname) {
const tmplCss = [ node.quasis.map(cooked) ]
function extractTemplateNodes (node) {
if (node.type !== 'TemplateLiteral') return
if (!node.parent || !node.parent.tag) return
if (node.parent.tag.name !== mname) return
const css = [ node.quasis.map(cooked) ]
.concat(node.expressions.map(expr)).join('').trim()
sheetify(tmplCss, filename, opts, function (tf) {
nodes.push([ tf, node.parent ])
})
const val = {
css: css,
filename: filename,
opts: xtend(opts),
node: node.parent
}
return
nodes.push(val)
}
// transform call references into files read from disk
// modify value node to prefix, and push css for transform
if (node.type === 'CallExpression' &&
node.callee && node.callee.type === 'Identifier' &&
node.callee.name === mname) {
// determine path
// - check if module import
// - don't prefix by default if module import
// - check if local file
function extractImportNodes (node) {
if (node.type !== 'CallExpression') return
if (!node.callee || node.callee.type !== 'Identifier') return
if (node.callee.name !== mname) return
const isLocalFile = /^\.{0,2}\//.test(node.arguments[0].value)
const localOptions = { global: !isLocalFile }
try {
var resolvePath = cssResolve(node.arguments[0].value, {
basedir: opts.basedir
basedir: path.dirname(filename)
})
} catch (err) {
if (err.message.substring(0, 18) !== 'Cannot find module') {
throw err
}
return self.emit('error', err)
}
const fnp = resolvePath ||
path.join(path.dirname(filename), node.arguments[0].value)
if (resolvePath) opts.global = true
else transformStream.emit('file', fnp)
try {
const fnCss = fs.readFileSync(fnp, 'utf8').trim()
// read optional arguments passed in to node
// e.g. { global: false }
if (node.arguments[1] && node.arguments[1].properties) {
const props = node.arguments[1].properties
props.forEach(function (prop) {
opts[prop.key.name] = prop.value.value
})
}
const iOpts = node.arguments[1]
? xtend(opts, localOptions, staticEval(node.arguments[1]))
: xtend(opts, localOptions)
sheetify(fnCss, fnp, opts, function (tf) {
nodes.push([ tf, node ])
})
const val = {
filename: resolvePath,
opts: iOpts,
node: node
}
return
} catch (e) {
const errMsg = 'sheetify: ' + e.path + ' cannot be imported'
return transformStream.emit('error', errMsg)
}
nodes.push(val)
}
}
// iterate over nodes, and apply sheetify transformation
// then replace the AST nodes with new values
// (obj, fn) -> null
function iterate (val, done) {
if (val.css) return handleCss(val)
fs.readFile(val.filename, 'utf8', function (err, css) {
if (err) return done(err)
val.css = css
handleCss(val)
})
function handleCss (val) {
sheetify(val.css, val.filename, val.opts, function (err, css, prefix) {
if (err) return done(err)
const str = [
"((require('insert-css')(" + JSON.stringify(css) + ')',
' || true) && ' + JSON.stringify(prefix) + ')'
].join('')
const lolSemicolon = (val.node.parent.type === 'VariableDeclarator')
? ''
: ';'
val.node.update(lolSemicolon + str)
done()
})
}
}
}

@@ -185,0 +161,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc