Skip to content

Commit

Permalink
added print method to style sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
daign committed Sep 6, 2023
1 parent cd90c84 commit 70e1429
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 8 deletions.
13 changes: 10 additions & 3 deletions lib/styleDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@ export interface IStyleDeclaration {

/**
* Parse the value of an attribute from string.
* @param name The name of the attribute.
* @param value The value as a string.
* @param name - The name of the attribute.
* @param value - The value as a string.
*/
parseAttribute( name: string, value: string ): void;

/**
* Copy style attributes from given style declaration but don't override already existing values.
* @param declaration The style declaration whose values to use.
* @param declaration - The style declaration whose values to use.
*/
complementWith( declaration: IStyleDeclaration ): void;


/**
* Return the concatenated style declaration as string.
* @returns The concatenated style declaration as string.
*/
printStyle(): string;
}
18 changes: 17 additions & 1 deletion lib/styleSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class StyleSelector {
/**
* Constructor.
* @param s - Concatenated string of several class names to initialize with. All starting with a
* period, e.g. '.controlPoint.selected'. Optional.
* dot, e.g. '.controlPoint.selected'. Optional.
*/
public constructor( s?: string ) {
if ( s && s.charAt( 0 ) === '.' ) {
Expand Down Expand Up @@ -50,4 +50,20 @@ export class StyleSelector {
* higher priority when processing style rules. */
return sign( this.classNames.length - selector.classNames.length );
}

/**
* Return the concatenated class names as string, each starting with a dot.
* @returns The concatenated class names as string.
*/
public printSelector(): string {
return this.classNames.map( ( item: string ): string => `.${item}` ).join( '' );
}

/**
* Return the concatenated class names as string, separated by spaces.
* @returns The concatenated class names as string.
*/
public printSelectorSpaced(): string {
return this.classNames.join( ' ' );
}
}
13 changes: 12 additions & 1 deletion lib/styleSelectorChain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class StyleSelectorChain {
/**
* Determine whether the chains match. Last selector must always match. From there on all
* selectors from the rule chain must match to selectors in the original chain in the given order,
* but in the original chain there can be addional selectors.
* but in the original chain there can be additional selectors.
* @param ruleChain - The selector chain to match with.
* @returns The boolean result of the match.
*/
Expand Down Expand Up @@ -145,4 +145,15 @@ export class StyleSelectorChain {

return result;
}

/**
* Return the concatenated style selectors as string, separated by space.
* @returns The concatenated style selectors.
*/
public printSelectorChain(): string {
return this.chain.map( ( selector: StyleSelector ): string => {
return selector.printSelector();
} )
.join( ' ' );
}
}
15 changes: 13 additions & 2 deletions lib/styleSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class StyleSheet<T extends IStyleDeclaration> {
// Comment detected, do nothing.

} else if ( emptyLineMatch !== null ) {
// Empty line dectected, do nothing.
// Empty line detected, do nothing.

} else {
// Line did not match any of the defined regular expressions for valid lines.
Expand All @@ -115,7 +115,7 @@ export class StyleSheet<T extends IStyleDeclaration> {
* @param rule - The style rule to add.
*/
private addRule( rule: StyleRule ): void {
/* Adding should keep the list sorted. Rules with higher priority come frist. If priority of two
/* Adding should keep the list sorted. Rules with higher priority come first. If priority of two
* rules is equal then the rule added last has the higher priority. Sorting must be stable.
* Therefore this implements its own sorting method similar to insertion sort. */
let index = 0;
Expand All @@ -131,4 +131,15 @@ export class StyleSheet<T extends IStyleDeclaration> {
// Insert at index position.
this.rules.splice( index, 0, rule );
}

/**
* Return the concatenated style sheet as CSS compatible string.
* @returns The concatenated style sheet as CSS compatible string.
*/
public printStyleSheet(): string {
return this.rules.map( ( rule: StyleRule ): string => {
return `${rule.selectorChain.printSelectorChain()} {${rule.declaration.printStyle()}}`;
} )
.join( '\n' );
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@daign/style-sheets",
"version": "1.1.0",
"version": "1.1.1",
"description": "Simple style sheet processor.",
"keywords": [
"style",
Expand Down
48 changes: 48 additions & 0 deletions test/styleSelector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,52 @@ describe( 'StyleSelector', (): void => {
expect( result ).to.equal( -1 );
} );
} );

describe( 'printSelector', (): void => {
it( 'should return the concatenated class names', (): void => {
// Arrange
const selector = new StyleSelector( '.a.b.c' );

// Act
const result = selector.printSelector();

// Assert
expect( result ).to.equal( '.a.b.c' );
} );

it( 'should return the empty string for empty selector', (): void => {
// Arrange
const selector = new StyleSelector( '' );

// Act
const result = selector.printSelector();

// Assert
expect( result ).to.equal( '' );
} );
} );

describe( 'printSelectorSpaced', (): void => {
it( 'should return the concatenated class names', (): void => {
// Arrange
const selector = new StyleSelector( '.a.b.c' );

// Act
const result = selector.printSelectorSpaced();

// Assert
expect( result ).to.equal( 'a b c' );
} );

it( 'should return the empty string for empty selector', (): void => {
// Arrange
const selector = new StyleSelector( '' );

// Act
const result = selector.printSelectorSpaced();

// Assert
expect( result ).to.equal( '' );
} );
} );
} );
27 changes: 27 additions & 0 deletions test/styleSelectorChain.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,4 +372,31 @@ describe( 'StyleSelectorChain', (): void => {
expect( result ).to.equal( 0 );
} );
} );

describe( 'printSelectorChain', (): void => {
it( 'should return the concatenated style selectors', (): void => {
// Arrange
const selectorChain = new StyleSelectorChain();
selectorChain.addSelector( new StyleSelector( '.a.b.c' ) );
selectorChain.addSelector( new StyleSelector( '.d.e' ) );
selectorChain.addSelector( new StyleSelector( '.f' ) );

// Act
const result = selectorChain.printSelectorChain();

// Assert
expect( result ).to.equal( '.a.b.c .d.e .f' );
} );

it( 'should return empty string for empty chain', (): void => {
// Arrange
const selectorChain = new StyleSelectorChain();

// Act
const result = selectorChain.printSelectorChain();

// Assert
expect( result ).to.equal( '' );
} );
} );
} );
44 changes: 44 additions & 0 deletions test/styleSheet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,48 @@ describe( 'StyleSheet', (): void => {
expect( badFn ).to.throw( 'Line 1 in style sheet could not be parsed.' );
} );
} );

describe( 'printStyleSheet', (): void => {
it( 'should return style sheet as string', (): void => {
// Arrange
const text =
`.a.b {
.c {
fill: green; stroke: black;
}
.d.e {
fill: blue;
}
fill: yellow;
}
.f {
fill: red;
}`;
const styleSheet = new StyleSheet<TestStyle>();
styleSheet.parseFromString( text, TestStyle );

// Act
const result = styleSheet.printStyleSheet();

// Assert
expect( result ).to.equal(
`.a.b .d.e {fill: blue}
.a.b .c {fill: green; stroke: black}
.a.b {fill: yellow}
.f {fill: red}`
);
} );

it( 'should return empty string for empty style sheet', (): void => {
// Arrange
const styleSheet = new StyleSheet<TestStyle>();
styleSheet.parseFromString( '', TestStyle );

// Act
const result = styleSheet.printStyleSheet();

// Assert
expect( result ).to.equal( '' );
} );
} );
} );
24 changes: 24 additions & 0 deletions test/testStyle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,28 @@ describe( 'TestStyle', (): void => {
expect( targetStyle.strokeWidth ).to.equal( 1.23 );
} );
} );

describe( 'printStyle', (): void => {
it( 'should return the concatenated style declaration', (): void => {
// Arrange
const style = new TestStyle( 'green', 'red', 1.23 );

// Act
const result = style.printStyle();

// Assert
expect( result ).to.equal( 'fill: green; stroke: red; stroke-width: 1.23' );
} );

it( 'should return empty string for empty declaration', (): void => {
// Arrange
const style = new TestStyle();

// Act
const result = style.printStyle();

// Assert
expect( result ).to.equal( '' );
} );
} );
} );
20 changes: 20 additions & 0 deletions test/testStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,24 @@ export class TestStyle implements IStyleDeclaration {
this.strokeWidth = declaration.strokeWidth;
}
}

/**
* Return the concatenated style declaration as string.
* @returns The concatenated style declaration as string.
*/
public printStyle(): string {
const attributes = [];

if ( this.fill ) {
attributes.push( `fill: ${this.fill}` );
}
if ( this.stroke ) {
attributes.push( `stroke: ${this.stroke}` );
}
if ( this.strokeWidth ) {
attributes.push( `stroke-width: ${this.strokeWidth}` );
}

return attributes.join( '; ' );
}
}

0 comments on commit 70e1429

Please sign in to comment.