Ramonda

What is checked

The syntax is not TypeScript, so the package owns a parser and a virtual-file layer — the same way JSX is usable because somebody wrote the parser for it. That layer is what buys the checking: a fault in a block arrives as an ordinary tsc diagnostic, on the character you wrote, in your own file.

What your editor tells you

  • A property that does not exist is TypeScript's own did you mean, on the property.
  • A value the property does not take is reported the same way, with the values it does take. A property whose grammar admits a name nobody can judge — animation-name: slidein is yours to pick — is left alone. A url() or a quoted string in the value does not make it one: cursor: url(a.cur), pointerr is still reported, on pointerr.
  • A hole is checked against the type the property accepts, in the scope where it was written. this.weight resolves to the field beside it, because the expression stays where you put it.
  • A condition or a selector spelled two ways is reported, with the spelling to use. @media (min-width:40rem) and @media (min-width: 40rem) are the same CSS, so writing both is writing two of what should be one thing.
  • A quoted value on a property with no place for a string is reported. Your editor completes a value from a real union the way it completes any string literal, so color: "yellow" is an easy thing to end up with — and it compiles, ships color:"yellow", and is dropped by every browser. content: "hi" and font-family: "Brand" are correct CSS and stay silent, because the question is asked of each property's own grammar.

One spelling

Two spellings of the same CSS are two things to search for and two to keep in step. Where a declaration, a condition or a selector has a canonical form, the other one is reported and ramonda-css format writes the canonical one:

const card = @@(
  COLOR: red;
  @media (min-width:40rem) { color: blue; }
);

Both of those are correct CSS — a browser reads COLOR and color as one property, and a media query with no space after the colon is the same query. What they cost is a second thing to grep for.

CSS does not mind either. Your repository does.

Inside a named block, the vocabulary is its own

@@keyframes, @@font-face and @@property each hold something different from an element's rule, and the check follows that:

writtenwhat happens
opacty: 1 in a framereported — a frame holds ordinary properties
form { … }reported — a frame is from, to or a percentage
opacity: 0 outside any framereported — it belongs to no time, so the browser drops it
@@font-face with no srcreported — the descriptor is required, and the face would load nothing
font-familly: "Brand"reported, with the descriptor you meant
@@property with no inheritsreported — measured, the browser drops the whole rule without it
initial-value its syntax does not acceptreported — measured, the browser drops the whole rule for that too
a registered property set to a value its syntax refusesreported — measured, the browser keeps the initial-value and says nothing
&:hover { … } in eitherreported — a descriptor list has no element to select against

A hole may not go in one of these at all: a hole is a custom property on an element, and these name something the whole stylesheet uses, so there is no element for the value to come from.

A media feature that will never match is the row worth pausing on, because it is not invalid CSS. A browser reads @media (min-widht: 40rem), keeps the rule, and never matches it — so every declaration inside is inert and nothing else has any reason to complain.

When a rule is wrong

Every rule here fails the build. There is no warning level, and that is deliberate: a warning nobody must act on is a warning nobody reads.

So there is one way to say I looked at this and it stays:

/* ramonda-css-ignore a vendor stylesheet defines this one */
display: flexx;

It covers the next line only, so it cannot creep past what you looked at. It works in a // comment too, for a finding about the block itself rather than about a line in it.

A reason is required. A directive with nothing after it is refused, and does not exempt the line below it either:

a ramonda-css-ignore with no reason after it is a silence, not a record.

And every one is printed on every run, whether or not anything failed:

[ramonda-css] 1 `ramonda-css-ignore`, honoured:

  src/Card.tsx:12  a vendor stylesheet defines this one

That is what makes it a record rather than a silence. A reason that has stopped being true is one somebody meets, instead of one they would have to go looking for.

What your project adds to that

Everything above is CSS being checked against itself, and it needs no config. A ramonda.css.ts adds reports that are yours rather than CSS's — a unit this project does not use, a value outside a list it gave, a shorthand it switched off, a colour written out where it takes colours from variables, a $ path it does not declare. Each is a row in the table below, and each fails the build the same way.

If that file cannot be read, your editor says so on the block. The completions keep working, but nothing is being checked against rules that did not load, and a green file would be a claim the tool cannot support:

[config-not-read] … does not parse: TS1136: Property assignment expected. Until it reads, none of this project's rules are running — this block is not being checked against them, and a build will refuse before it gets here.

Every rule

A typo in one of these ids is caught too: writing unknown-unti in ramonda.css.ts tells you so, and names the one you meant.

Every one of them fails the build. 41 of them, and each is a key you can switch off.

rulereported when
unknown-propertya property name that is nearly one CSS has
unknown-valuea word this property does not take
repeated-declarationthe same property set twice to the same value
hole-out-of-placea hole where CSS needs text, like a property name
block-as-a-jsx-attributecss=@@( … ) — a block is a value, so it goes in the braces
run-on-declarationa missing ;, so the next line joined this value
line-commenta // comment, which CSS does not have
unknown-unita unit CSS does not have
glued-holetext written against a hole, which is not part of its value
at-rule-out-of-placean at-rule that names something for the whole stylesheet
unknown-framea keyframe selector that is not one
declaration-out-of-placea declaration where only a rule belongs
rule-out-of-placea nested rule where only declarations belong
override-out-of-ordera declaration written to override one that will win anyway
variable-set-by-another-namea var() reading a name set with different capitals
hole-as-a-variable-namea hole naming a custom property rather than holding a value
initial-value-and-syntax@@property with a syntax and no initial value
unknown-media-featurea media feature that will never match
value-and-registered-syntaxa value a registered custom property cannot hold
unit-not-alloweda unit your ramonda.css.ts does not allow
value-not-alloweda value outside the closed list your ramonda.css.ts gave this property
shorthand-not-alloweda shorthand your ramonda.css.ts switched off — write its longhands
string-not-alloweda quoted value where the property takes a keyword
property-not-a-namea value that must name a property and does not
non-canonical-spellingone CSS written two ways — ramonda-css format fixes it
layer-in-a-block@layer inside a block, which the sheet already decides
spread-out-of-place...{block} somewhere a whole block cannot go
hole-in-a-named-blocka hole in @@keyframes( … ) and its kind, which have no element
unknown-named-block@@name( … ) where the name is not a site this compiles
composition-in-a-named-block...{block} inside a named site, which composes nothing
ignore-without-a-reasonramonda-css-ignore with nothing after it
unknown-prefixa vendor prefix that is not one of the four
unknown-at-rulean at-rule name CSS does not have
unknown-selectora pseudo-class or pseudo-element that is not one — the whole rule is dropped
unknown-flaga ! at the end of a value that is not !important
unclosed-calla ( in a value that no ) closes — the value runs past the end of the block
unknown-variable$.… naming a variable your ramonda.css.ts does not declare
too-many-valuesmore values than the property takes — in CSS, or in your ramonda.css.ts
missing-semicolona declaration with no ;, which swallows the line written under it
literal-not-alloweda value written out where your ramonda.css.ts takes that kind from variables
declaration-does-nothinga declaration another one on the same element switches off — valid CSS the browser ignores

Next

  • The config file — switching a rule off, and making the rest stricter than CSS is.
  • Tooling — what your formatter and linter can and cannot read.