import { describe, expect, test } from 'vitest'
import { toCss } from './ast'
import { SignatureFeatures } from './canonicalize-candidates'
import { parse } from './css-parser'
import { expandDeclaration } from './expand-declaration'
import { walk, WalkAction } from './walk'
const css = String.raw
function expand(input: string, options: SignatureFeatures): string {
let ast = parse(input)
walk(ast, (node) => {
if (node.kind === 'declaration') {
let result = expandDeclaration(node, options)
if (result) return WalkAction.ReplaceSkip(result)
}
})
return toCss(ast)
}
describe('expand declarations', () => {
let options = SignatureFeatures.ExpandProperties
test('inset', () => {
let input = css`
.one {
inset: 10px;
}
.two {
inset: 10px 20px;
}
.three {
inset: 10px 20px 30px;
}
.four {
inset: 10px 20px 30px 40px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
}
.two {
top: 10px;
right: 20px;
bottom: 10px;
left: 20px;
}
.three {
top: 10px;
right: 20px;
bottom: 30px;
left: 20px;
}
.four {
top: 10px;
right: 20px;
bottom: 30px;
left: 40px;
}
"
`)
})
test('gap', () => {
let input = css`
.one {
gap: 10px;
}
.two {
gap: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
row-gap: 10px;
column-gap: 10px;
}
.two {
row-gap: 10px;
column-gap: 20px;
}
"
`)
})
test('border-width', () => {
let input = css`
.one {
border-width: 1px;
}
.two {
border-width: 1px 2px;
}
.three {
border-width: 1px 2px 3px;
}
.four {
border-width: 1px 2px 3px 4px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
}
.two {
border-top-width: 1px;
border-right-width: 2px;
border-bottom-width: 1px;
border-left-width: 2px;
}
.three {
border-top-width: 1px;
border-right-width: 2px;
border-bottom-width: 3px;
border-left-width: 2px;
}
.four {
border-top-width: 1px;
border-right-width: 2px;
border-bottom-width: 3px;
border-left-width: 4px;
}
"
`)
})
test('border-style', () => {
let input = css`
.one {
border-style: solid;
}
.two {
border-style: solid dashed;
}
.three {
border-style: solid dashed dotted;
}
.four {
border-style: solid dashed dotted double;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
}
.two {
border-top-style: solid;
border-right-style: dashed;
border-bottom-style: solid;
border-left-style: dashed;
}
.three {
border-top-style: solid;
border-right-style: dashed;
border-bottom-style: dotted;
border-left-style: dashed;
}
.four {
border-top-style: solid;
border-right-style: dashed;
border-bottom-style: dotted;
border-left-style: double;
}
"
`)
})
test('border-color', () => {
let input = css`
.one {
border-color: red;
}
.two {
border-color: red green;
}
.three {
border-color: red green blue;
}
.four {
border-color: red green blue black;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
border-top-color: red;
border-right-color: red;
border-bottom-color: red;
border-left-color: red;
}
.two {
border-top-color: red;
border-right-color: green;
border-bottom-color: red;
border-left-color: green;
}
.three {
border-top-color: red;
border-right-color: green;
border-bottom-color: blue;
border-left-color: green;
}
.four {
border-top-color: red;
border-right-color: green;
border-bottom-color: blue;
border-left-color: black;
}
"
`)
})
test('scroll-margin', () => {
let input = css`
.one {
scroll-margin: 1px;
}
.two {
scroll-margin: 1px 2px;
}
.three {
scroll-margin: 1px 2px 3px;
}
.four {
scroll-margin: 1px 2px 3px 4px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
scroll-margin-top: 1px;
scroll-margin-right: 1px;
scroll-margin-bottom: 1px;
scroll-margin-left: 1px;
}
.two {
scroll-margin-top: 1px;
scroll-margin-right: 2px;
scroll-margin-bottom: 1px;
scroll-margin-left: 2px;
}
.three {
scroll-margin-top: 1px;
scroll-margin-right: 2px;
scroll-margin-bottom: 3px;
scroll-margin-left: 2px;
}
.four {
scroll-margin-top: 1px;
scroll-margin-right: 2px;
scroll-margin-bottom: 3px;
scroll-margin-left: 4px;
}
"
`)
})
test('scroll-padding', () => {
let input = css`
.one {
scroll-padding: 1px;
}
.two {
scroll-padding: 1px 2px;
}
.three {
scroll-padding: 1px 2px 3px;
}
.four {
scroll-padding: 1px 2px 3px 4px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
scroll-padding-top: 1px;
scroll-padding-right: 1px;
scroll-padding-bottom: 1px;
scroll-padding-left: 1px;
}
.two {
scroll-padding-top: 1px;
scroll-padding-right: 2px;
scroll-padding-bottom: 1px;
scroll-padding-left: 2px;
}
.three {
scroll-padding-top: 1px;
scroll-padding-right: 2px;
scroll-padding-bottom: 3px;
scroll-padding-left: 2px;
}
.four {
scroll-padding-top: 1px;
scroll-padding-right: 2px;
scroll-padding-bottom: 3px;
scroll-padding-left: 4px;
}
"
`)
})
test('overflow', () => {
let input = css`
.one {
overflow: clip;
}
.two {
overflow: hidden visible;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
overflow-x: clip;
overflow-y: clip;
}
.two {
overflow-x: hidden;
overflow-y: visible;
}
"
`)
})
test('overscroll-behavior', () => {
let input = css`
.one {
overscroll-behavior: none;
}
.two {
overscroll-behavior: auto contain;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
overscroll-behavior-x: none;
overscroll-behavior-y: none;
}
.two {
overscroll-behavior-x: auto;
overscroll-behavior-y: contain;
}
"
`)
})
test('expansion with `!important`', () => {
let input = css`
.one {
inset: 10px;
}
.two {
inset: 10px 20px;
}
.three {
inset: 10px 20px 30px !important;
}
.four {
inset: 10px 20px 30px 40px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".one {
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
}
.two {
top: 10px;
right: 20px;
bottom: 10px;
left: 20px;
}
.three {
top: 10px !important;
right: 20px !important;
bottom: 30px !important;
left: 20px !important;
}
.four {
top: 10px;
right: 20px;
bottom: 30px;
left: 40px;
}
"
`)
})
})
describe('expand logical properties', () => {
let options = SignatureFeatures.ExpandProperties | SignatureFeatures.LogicalToPhysical
test('margin-inline', () => {
let input = css`
.example {
margin-inline: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
margin-left: 10px;
margin-right: 20px;
}
"
`)
})
test('margin-block', () => {
let input = css`
.example {
margin-block: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
margin-top: 10px;
margin-bottom: 20px;
}
"
`)
})
test('padding-inline', () => {
let input = css`
.example {
padding-inline: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
padding-left: 10px;
padding-right: 20px;
}
"
`)
})
test('padding-block', () => {
let input = css`
.example {
padding-block: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
padding-top: 10px;
padding-bottom: 20px;
}
"
`)
})
test('scroll-margin-inline', () => {
let input = css`
.example {
scroll-margin-inline: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
scroll-margin-left: 10px;
scroll-margin-right: 20px;
}
"
`)
})
test('scroll-margin-block', () => {
let input = css`
.example {
scroll-margin-block: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
scroll-margin-top: 10px;
scroll-margin-bottom: 20px;
}
"
`)
})
test('scroll-padding-inline', () => {
let input = css`
.example {
scroll-padding-inline: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
scroll-padding-left: 10px;
scroll-padding-right: 20px;
}
"
`)
})
test('scroll-padding-block', () => {
let input = css`
.example {
scroll-padding-block: 10px 20px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
scroll-padding-top: 10px;
scroll-padding-bottom: 20px;
}
"
`)
})
test('border-inline-width', () => {
let input = css`
.example {
border-inline-width: 1px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
border-left-width: 1px;
border-right-width: 1px;
}
"
`)
})
test('border-block-width', () => {
let input = css`
.example {
border-block-width: 1px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
border-bottom-width: 1px;
border-top-width: 1px;
}
"
`)
})
test('border-inline-style', () => {
let input = css`
.example {
border-inline-style: 1px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
border-left-style: 1px;
border-right-style: 1px;
}
"
`)
})
test('border-block-style', () => {
let input = css`
.example {
border-block-style: 1px;
}
`
expect(expand(input, options)).toMatchInlineSnapshot(`
".example {
border-bottom-style: 1px;
border-top-style: 1px;
}
"
`)
})
})