Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Created November 19, 2019 17:14
Show Gist options
  • Save tomhodgins/42c76e3852333473f968d22a3f27c412 to your computer and use it in GitHub Desktop.
Save tomhodgins/42c76e3852333473f968d22a3f27c412 to your computer and use it in GitHub Desktop.
just playing around with a command line tool to parse package.css files
import * as parseCSS from 'https://tomhodgins.github.io/parse-css/index.js'
const input = {
css: '',
js: ''
}
const output = {
css: '',
js: ''
}
cpm(Deno.args[1])
async function cpm(path = './') {
let file = ''
// Resolve package.css or input stylesheet
if (
path === undefined
&& await fileInfo('package.css', file => file.isFile())
) {
file = await getFileText('package.css')
}
if (path) {
if (await fileInfo(path, file => file.isFile())) {
file = await getFileText(path)
}
if (
await fileInfo(path, dir => dir.isDirectory())
&& await fileInfo(`${path}/package.css`, file => file.isFile())
) {
file = await getFileText(`${path}/package.css`)
}
}
// If stylesheet found and contains @--package rule…
if (file) {
const stylesheet = parseCSS.parseAStylesheet(file)
if (
stylesheet
&& stylesheet.type
&& stylesheet.type === 'STYLESHEET'
&& stylesheet.value
&& stylesheet.value.length
&& hasPackageAtRule(stylesheet)
) {
processPackageAtRules(stylesheet)
}
}
console.log(
input,
output
)
}
async function fileInfo(string, test = info => info) {
try {
const info = await Deno.stat(string)
return test(info)
}
catch(error) {
if (
error
&& error.kind === Deno.ErrorKind.NotFound
) {
return false
} else {
throw error
}
}
}
async function getFileText(string = '') {
return new TextDecoder('utf-8').decode(
await Deno.readFile(string)
)
}
async function getTextFromURL(url = '') {
let text = ''
if (await fileInfo(url, file => file.isFile())) {
text = await getFileText(url)
} else {
try {
let response = await fetch(url)
text = await response.text()
}
catch(error) {
throw error
}
}
return text
}
function hasPackageAtRule(styletsheet = {value: {}}) {
return styletsheet.value.find(({type, name}) =>
type === 'AT-RULE' && name === '--package'
) !== undefined
}
function processPackageAtRules(stylesheet = {value: {}}) {
stylesheet.value.filter(({type, name}) =>
type === 'AT-RULE' && name === '--package'
).forEach(processCSSPackage)
}
async function processCSSPackage(rule) {
const object = parsePackageAtRule(rule)
// handle stylesheets
if (object.stylesheets) {
object.stylesheets
.filter(({type, name}) => type === 'FUNCTION' && name === 'url')
.map(({value}) => value[0].value)
.forEach(async url => {
input.css += await getTextFromURL(url)
})
}
// handle scripts
// handle commands
// replace CSS
// create temp CSS file to be represented as $css
// create temp JS file to be represented as $js
// process CSS file as a package
// fetch any linked files
// concatenate files into $css temp file
// process concatenated files with list of command() instructions
// log package.css stylesheet with @--package rule replaced by processed CSS output
// output CSS and JS
// questions
// how to handle other files (and we just make them by naming $something in a command?)
}
function parsePackageAtRule(rule) {
const object = {}
const declarations = parseCSS.parseAListOfDeclarations(
rule.value.value
.map(token => token.toSource())
.join('')
)
const properties = [
'name',
'description',
'license',
'authors',
'homepage',
'stylesheets',
'plugins',
'commands',
// 'test', ?
// 'tools' ?
]
// Extract properties from CSS
properties
.map(property => declarations.find(({name}) => name === property))
.filter(Boolean)
.forEach(({name, value}) => object[name] = value)
return object
}
function sringifyPackageAtRule(object) {
return `
@--package {
${Object.entries(object).map(([key, value]) => `${key}: ${value};`).join(' ')}
}
`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment