Skip to content

ec429/css-tools

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

css-tools - make sense of your CSS
===Documentation===

==Note==
It is important to remember that *none of the css-tools is a validator*.  Where a css-tool includes a parser, the parser may fail in either of two ways.
(i) it may reject or misinterpret a valid construct.  Such a failure is a bug to be fixed and should be reported as such.
(ii) it may accept an invalid construct.  While undesirable, this behaviour is not a bug, rather it is the lack of a feature (the feature concerned being 'rejection of invalid construct X').  Thus, this failure should be reported as a feature request, if at all.
You should always validate your code prior to deployment, and you should do so with proper validation tools (such as the W3C HTML and XML online validators); "css-tools parsed it with no errors" is simply not enough.

==CSSI==

	cssi [-d][-t] [-I=<importpath>] [-W[no-]<warning> [...]] <filename> [...]

cssi is a command-line program which reads and parses one or many CSS files, then presents you with a shell from which you can query their structure.
Remember that *cssi is not a validator*; it accepts some invalid constructs, and probably rejects some valid ones (although the latter would be a bug).
Daemon mode: Output is sent, in a terse form, to stdout.  This is designed to allow front-end tools and interfaces to use cssi.  Some long-form output will still be produced, but redirected to stderr.
Options:
	-d,--daemon		Run in daemon mode
	-h,--help		Invocation help
	-t,--trace		Trace the parser state-machine (for debugging)
	-w,--max-warn=<maxwarnings>
					Output of warning messages stops after the <maxwarnings>th.  Default is 10
	-Wall,-Wno-all	Enable/disable all warnings
	-W<warning>		Enable the specified warning
	-Wno-<warning>	Disable the specified warning
	-I=<importpath>	Sets the path to use for @import at-rules (default is the current directory)
A filename of - (dash) will cause cssi to read from stdin.
An <importpath> (-I) will only affect files that come /after/ it on the command line.  @imported files will inherit the importpath of the (first) file which imported them.  If the path given does not end in a slash '/', one will be appended.
Warnings:
	-Wnewline		Missing newline; two rules on the same line.  Default TRUE
	-Wdupfile		Duplicate file; duplicates are always skipped whether the warning is on or not.  Default TRUE
	-Watrule		At-rule positioning; an at-rule appears somewhere other than the start of a line, or is inside a selector.  Default TRUE
Commands for the cssi shell:
	selector [[!]<param>[<comparator><match>] [...]]
		Lists selectors matching the specified params.  If a param is preceded by '!', its sense is inverted
		Valid <param>s:
			sid		the SelId of the selector (SelId is an internally-generated primary key)
			file	the path/name of the file in which the selector appears
			line	the line-number of the statement containing the selector
			match	a tree-walk to which the selector must apply.  Only takes '=' and its semantics are changed to 'applies to'.  See section 'Tree-matching' below.
			dup		NZ if the selector has duplicates, 0 otherwise
			last	boolean - was the selector matched by the last search done?  (ie. search within results)
			rows	max number of rows to show.  Effectively, row-number<value, where row-number is incremented each time a row is shown
		Valid <comparator>s:
			=		equality
			<, >	gt/lt for numerics
			<=, >=	ge/le for numerics
			:		satisfies regex
			no comparator: test nonzero
		Param matches are ANDed together
	declaration [[!]<param>[<comparator><match>] [...]]
		Lists the inner code (what's between the braces) of the selectors matching the specified params.
		Valid params etc. are as for selector
	quit
		Quits cssi
You only need to use enough characters of the command name to match it unambiguously.  The same does *not* apply to arguments, which must be given in full.
Arguments are space-delimited.
		
Sample usage of cssi:
	$ ./cssi -I=/path/to/css/ /path/to/css/test.css /path/to/css/sub.css
		cssi: processing test.css
		cssi: parsed test.css
		cssi: processing sub.css
		cssi: parsed sub.css
		cssi: warning: Duplicate file in set (from @import): sub.css
		cssi: Parsing completed
		cssi: collating & parsing selectors
		cssi: collated & parsed selectors
		cssi>sel dup rows=10
		cssi: matching SELECTORS
		3* In test.css at 67:   a:hover
		4+ In sub.css at 9:     a:hover
		11*     In test.css at 222:     img
		12+     In sub.css at 173:      img
		89*     In test.css at 520:     #articles
		90+     In sub.css at 141:      #articles
		92*     In test.css at 734:     #bannerad
		93+     In sub.css at 17:       #bannerad
		95*     In test.css at 34:      #bodydiv
		96+     In sub.css at 23:       #bodydiv
		cssi>q
	$

Tree-matching:
NOTE: Tree-matching hasn't been completely implemented yet.
See the section "Implementation Status" below.
Format of a tree-match, in something approximating BNF:
	<tree-match>::=	<prepension>?<html-tag>?<property>*(<relation><tree-match>)?
	<property>	::=	{<class>|<pclass>|<id>}
	<relation>	::=	{>|\+}
	<html-tag> any of the tags listed in tags.h
	<class>		::=	\.<ident>
	<pclass>	::=	:<ident>
	<id>		::=	#<ident>
	<prepension>::= {\?|<number>}
	<ident>		::=	<nmstart><nmchar>*
	<nmstart>	::=	[_a-z]
	<nmchar>	::=	[_a-z0-9-]
	<number>	::= [0-9]+
Note that this considerably restricts the range of permissible identifiers as compared to the W3C CSS2.1 specification.  In particular, escapes (such as "\00000a") are not supported in css-tools right now.  Then again, it baffles me as to why you'd want to use them.
The input parser doesn't actually enforce these rules - for example, you _can_ use "\00000a" - but since it doesn't recognise them either, you might not get the results you're expecting.  Thus, it's usually best to constrain your input (and your stylesheets!) to simple, sensible identifiers.
Whitespace is disallowed because ' ' delimits command arguments, and it's never needed.  But, you might ask, what about the Descendant syntax?  Well, that's for /selectors/, you can't use it for your tree-match.  After all, if you did, how would cssi know whether your "p a" should match the selector "p>a"?  Of course, "p>a" always matches the selector "p a", but it's not symmetric.
A <relation> must always be given, partly because trying to match a Descendant entry in a tree against a selector is ambiguous and/or meaningless; partly also to delimit strings as otherwise eg. "div#mydiv" would be ambiguous (is it <div id="mydiv" />, or <div id="my"><div /></div>?).
How it works: Suppose you have the following HTML tree (truncated):
	<html>
		<body>
			<div id="main">
				<h1 class="title">
					My Page
				</h1>
				<h2>
					Table of Contents
				</h2>
				<p class="toc">
					<table>
						<tr><td class="foo"><a href="#foo">The Koans of Master Foo</a></td></tr>
						<tr><td class="bar"><a href="#bar">Propping up the Bar</a></td></tr>
					</table>
				<h2 id="foo">
					The Koans of Master Foo
				</h2>...
Now suppose you want to match the link to 'Propping up the Bar' in the table of contents.  There are several ways you could specify it:
	match=.toc>>>td.bar>a
	match=.bar>a
	match=tr+tr>td>a
	match=html>body>div#main>p.toc>table>tr>td.bar>a
All of these would, in the above snippet, uniquely specify that link.  The most specific tree-match, however, would be
	match=html>body:first-child>div#main>h1:first-child.title+h2+p.toc>table:first-child>tr:first-child+tr>td:first-child.bar>a:first-child[href="#bar"]
(Although, note that this wouldn't work right now as the [attribute] selector is not yet supported.)
Remember also that you're not actually aiming to uniquely specify an element in your tree, because cssi isn't looking at your tree, but at your CSS.
So if you just used match=.bar>a, this would also match the CSS selectors "h1 a" and "td>>a", neither of which match that element.  The 'most specific' match above describes everything CSS 'knows' about the element.
The matcher is 'optimistic': it returns all the selectors which could conceivably describe the element - it assumes that you have told it the truth but not the whole truth.  The only exception to this is ID selectors; if you don't specify one, it assumes the element has no ID, rather than any ID.  To make the matcher optimistic about an element's ID, give an ID of "?" (which is not a valid ID in CSS2.1).  So the selector "p#bar" would be matched by "match=p#?" - and even "match=.foo>p#?" - but not "match=p".  Also, of course, if you specify a tag, that excludes any other tags; the same however does /not/ apply to classes and pclasses, which are not mutually exclusive.  "?" will force optimism on any selector, not just IDs.
The matcher is aware of the meanings of at least some pclasses, so for instance it knows that "match=tr+tr" can't match the rule ":firstchild".
The matcher also assumes ("prepension") that there exists an infinite string of elements outside the tree you have given; so for example "match=a" will match the selectors "div>p a" and "* * * * * * * * * * * * * * a".  If you want to suppress this behaviour, prepend the match with a number (since a <tree-match> conforming to the above grammar cannot begin with a digit) specifying how many elements may be prepended; for this purpose descendant selectors will only prepend a single element, as though they were child selectors; also sibling selectors will be considered not to prepend any elements.  A prepension limit of "?" specifies infinite prepension, as in the default.
To make the matcher pessimistic about classes or pclasses (or IDs, if they are set to be optimistic), specify an empty string for them; so "match=p." won't match the rule ".toc", but it will match the rules "div.toc>p" and "p:firstchild".  If you want to specify that an element has, say, the class "foo" /and no others/, use "match=.foo."; this will match "div>p.foo" but not "p" or "p.bar".
An empty element is considered to be a universal match; it is /always/ matched optimistically, regardless of other settings; so "p>>div" will match "*>.foo:bar#baz>*" no matter what - and will match ".puddle:paddle#peddle>*>.foo:bar#baz>*" if prepension is permitted, because prepended elements are 'empty elements'.  Also, since every element must have a tag, if no tag is given for an element then tags will be matched optimistically, so ".toc>table" will match the rule "p>table" regardless of tag optimism settings.
You can also set optimism/pessimism for an entire matcher (apart from prepension) in one go, by using either "matcho" or "matchp", or match0 through match7 to set the optimism bitmask where 4=id,2=class,1=pclass.  So matcho is match7, matchp is match0, and match is match3.  There is no point having an optimism setting for tags, since either a tag is given (in which case pessimism is implied) or no tag is given (in which case optimism is implied).
So with all of these things included, the 'most specific' tree-match, which will match precisely those rules which apply to that link, becomes:
	matchp=0html>body:first-child>div#main>h1:first-child.title+h2+p.toc>table:first-child>tr:first-child+tr>td:first-child.bar>a:first-child[href="#bar"]
The matcher is case-sensitive.
The default optimism and prepension settings should be alterable with some kind of option command (and cmdline options).

Implementation status:
The matcher basically functions, now, except that pessimism is forced (ie. the optimism settings are not supported and the default is matchp).

==CSSCOVER==

	csscover [-d][-t][-c] [-I=<importpath>] [-W[no-]<warning> [...]] <htmlfile> [...]

csscover is a command-line program which reads and parses one or more HTML files, then (with the help of cssi) determines which CSS rules in which files apply to them; it's basically to help you find unused (or hardly-used) CSS code.
Remember that *csscover is not a validator*; it accepts some invalid constructs, and probably rejects some valid ones (although the latter would be a bug).
Daemon mode: Output is sent, in a terse form, to stdout.  This is designed to allow front-end tools and interfaces to use csscover.  Some long-form output will still be produced, but redirected to stderr.
Options:
	-d,--daemon		Run in daemon mode
	-h,--help		Invocation help
	-t,--trace		Trace the parser state-machine and other things (for debugging)
	-c,--hide_child_msgs
					Prevent the child process (which should be daemon-mode cssi) from writing its long-form output to stderr
	-w,--max-warn=<maxwarnings>
					Output of warning messages stops after the <maxwarnings>th.  Default is 10
	-Wall,-Wno-all	Enable/disable all warnings
	-W<warning>		Enable the specified warning
	-Wno-<warning>	Disable the specified warning
	-I=<importpath>	Sets the path to use for @import at-rules (default is the current directory)
A filename of - (dash) will cause cssi to read from stdin.
An <importpath> (-I) will only affect files that come /after/ it on the command line.  @imported files will inherit the importpath of the (first) file which imported them.  If the path given does not end in a slash '/', one will be appended.
Warnings:
	-Wdupfile		Duplicate file; duplicates are always skipped whether the warning is on or not.  Default TRUE
	-Wdtd			Various warnings concerning Document Type Declarations (<!DOCTYPE>).  Default TRUE
	-Wquoteattr		Attribute values given without enclosing quotes.  Default TRUE
	-Wclose			Element(s) left open at end-of-file.  Default TRUE
	-Wver-mismatch	Child process is from a different version of css-tools.  Default TRUE
	-Wcase			Upper-case has been used for an element or attribute name in HTML.  Default TRUE
Commands for the csscover shell:
	selector [<cssi-param> [...]] [usage[<comp><value>]]
		Lists selectors matching the specified params.  Not implemented yet
		<cssi-param>s are tests which would be valid arguments to the 'selector' command in cssi
		<comp> may be any of:
			=	equals
			<	less than
			>	greater than
			<=	less than or equal to
			>=	greater than or equal to
			!=	does not equal
		<value> is evaluated as a decimal number
		If no <comp><value> pair is given to a usage argument, it shall be equivalent to 'usage!=0'
	dump <filename>
		Writes out the usage table to <filename> in a format to be defined at a later date
	quit
		Quits csscover
You only need to use enough characters of the command name to match it unambiguously.  The same does *not* apply to arguments, which must be given in full.
Arguments are space-delimited.
If you try to enter a command while the previous command is being (asychronously) processed, the sequencer will reject the input with an EBUSY.  The long-form error message for this is "Busy talking to the kids", ie. the child process.
Known Issues:
	For the parser to accept the HTML file, elements must be correctly nested and must be explicitly closed before closing their parent element.  While this is the requirement under XHTML, there are some cases where HTML permits it (such as <br>, which in XHTML becomes the self-closing <br />; or <div><p></div> where the P is implicitly closed).  For this reason, if using css-tools you are advised to use XHTML for your site.  In the future css-tools will (hopefully) support HTML's automatic closure.
	Attribute values cannot be enclosed in 'single quotes', only "double quotes".  This will hopefully be fixed at some point in the future.
	[X]HTML comments are handled in an incorrect manner: <!-- is treated as an 'open comment delimiter' and --> as a 'close comment delimiter'.  This is contrary to the HTML specification in which <! and > delimit an SGML declaration and -- delimits a comment within a declaration, or equivalently to the XHTML specification in which, although <!-- and --> do delimit a comment, -- must not appear in the body of a comment.  The correct behaviour for a validator would be to reject invalid comment forms; however, many authors write - and, as a result, several User-Agents accept - such invalid comments.  Also, the validity of a comment may depend on the DTD, as, for instance, HTML allows whitespace between the -- and the > closing a comment, whereas XML does not - and csscover doesn't parse the <!DOCTYPE> declaration (and in any case, one might not be present).  Hence, the correct behaviour for csscover is to accept anything that could be a valid comment, but generate a warning on anything that could be an invalid comment (for instance, <!--comment-- > and <!--a----b--> should be accepted with a warning, whereas <! --comment--> and <!--a---> should be rejected as they are invalid in both HTML and XHTML).  However, the current behaviour is overly permissive (rather than overly restrictive) and is therefore not a bug (since csscover *is not a validator*).
	csscover isn't finished yet, and doesn't have the selector command yet; only dump and quit.

About

Make sense of your CSS

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages