Skip to content

Commit eee9ded

Browse files
committed
fix:style: Refactored code for better typing and readability
1 parent 9b167e9 commit eee9ded

File tree

15 files changed

+259
-160
lines changed

15 files changed

+259
-160
lines changed

src/nodes/document.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import postcss from "postcss";
2+
import { StyleRoot } from "./root.js";
3+
4+
export declare class Document extends postcss.Document {
5+
nodes: StyleRoot[];
6+
}

src/nodes/document.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as postcss from "postcss";
2+
import { stringify } from "../index.js";
3+
4+
/**
5+
* A customized PostCSS Document node.
6+
*
7+
* @augments {postcss.Document}
8+
*/
9+
export class Document extends postcss.Document {
10+
/**
11+
* It compiles the node to browser readable cascading style sheets string depending on it's type.
12+
*
13+
* @param {(postcss.Stringifier | postcss.Syntax)} [stringifier] - Optional stringifier to customize the output format.
14+
* @returns {string} The compiled CSS string of this node.
15+
*/
16+
toString(stringifier) {
17+
return super.toString(
18+
stringifier || {
19+
stringify: stringify,
20+
},
21+
);
22+
}
23+
}

src/nodes/root.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import postcss from "postcss";
2+
import { RootProps, RootRaws } from "postcss/lib/root";
3+
4+
interface StyleRaws extends RootRaws {
5+
stringType: '"' | "'" | "`";
6+
}
7+
8+
interface StyleProps extends RootProps {
9+
raws: StyleRaws;
10+
}
11+
12+
export declare class StyleRoot extends postcss.Root {
13+
raws: StyleRaws;
14+
constructor(options?: StyleProps);
15+
}

src/nodes/root.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as postcss from "postcss";
2+
import stringify from "../stringify.js";
3+
4+
/**
5+
* A customized PostCSS Root node with extended raw properties.
6+
*
7+
* @augments {postcss.Root}
8+
* @property {import("./types").StyleRaws} raws - Extended raw properties for StyleRoot.
9+
*/
10+
export class StyleRoot extends postcss.Root {
11+
/**
12+
* Creates an instance of StyleRoot.
13+
*
14+
* @class
15+
* @param {import("./root.js").StyleProps} options - Properties to initialize the StyleRoot instance.
16+
*/
17+
constructor(options) {
18+
super(options);
19+
}
20+
21+
/**
22+
* Compiles the node to a CSS string using the specified stringifier.
23+
*
24+
* @param {(postcss.Stringifier | postcss.Syntax)} [stringifier] - Optional stringifier to customize the output format.
25+
* @returns {string} The compiled CSS string of this node.
26+
*/
27+
toString(stringifier) {
28+
return super.toString(
29+
stringifier || {
30+
stringify: stringify,
31+
},
32+
);
33+
}
34+
}

src/parse.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Document, Input } from "postcss";
2-
import { AngularParser } from "./parser-angular.js";
2+
import { parseAngular } from "./parser/parser-angular.js";
33

44
/**
55
* Represents an object that can be converted to a string.
@@ -19,8 +19,5 @@ import { AngularParser } from "./parser-angular.js";
1919
export default function parse(angularCode, opts) {
2020
const input = new Input(angularCode.toString(), opts);
2121

22-
const angularParser = new AngularParser(input);
23-
angularParser.parse(opts);
24-
25-
return angularParser.doc;
22+
return parseAngular(input, opts);
2623
}

src/parser-angular.js

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,46 @@ import { Project, SyntaxKind } from "ts-morph";
44
* @typedef {import("ts-morph").StringLiteral | import("ts-morph").NoSubstitutionTemplateLiteral} StyleLiteral
55
*/
66

7-
export class TypescriptParser {
8-
/**
9-
* Creates an instance of TypescriptParser.
10-
*
11-
* @param {import("postcss").Input} input - The PostCSS input containing the source CSS and its originating file.
12-
*/
13-
constructor(input) {
14-
const project = new Project({
15-
useInMemoryFileSystem: true,
16-
});
7+
/**
8+
* Parses TypeScript source to extract style literals from component decorators.
9+
*
10+
* @param {import("postcss").Input} input - The PostCSS input containing the source CSS and its originating file.
11+
* @returns {StyleLiteral[]} An array of style literals extracted from the components within the source file.
12+
*/
13+
export function parseTypescript(input) {
14+
const project = new Project({
15+
useInMemoryFileSystem: true,
16+
});
1717

18-
this.sourceFile = project.createSourceFile(input.from, input.css);
19-
}
18+
const sourceFile = project.createSourceFile(input.from, input.css);
19+
return extractStyleLiterals(sourceFile);
20+
}
2021

21-
/**
22-
* Parses the TypeScript source file to extract style literals from component decorators.
23-
*
24-
* @returns {StyleLiteral[]} An array of style literals extracted from the components within the source file.
25-
*/
26-
parse() {
27-
return this.sourceFile
28-
.getClasses()
29-
.flatMap((cls) => cls.getDecorators())
30-
.filter(isComponentDecorator)
31-
.flatMap((decorator) => decorator.getArguments())
32-
.filter(isObjectLiteral)
33-
.flatMap(getStylesProperty)
34-
.flatMap(getStyleValues)
35-
.map(castToStyleLiteral);
36-
}
22+
/**
23+
* Extracts style literals from a source file.
24+
*
25+
* @param {import("ts-morph").SourceFile} sourceFile - The TypeScript source file to parse.
26+
* @returns {StyleLiteral[]} An array of extracted style literals.
27+
*/
28+
function extractStyleLiterals(sourceFile) {
29+
return sourceFile
30+
.getClasses()
31+
.flatMap(getComponentDecorators)
32+
.flatMap(getDecoratorArguments)
33+
.filter(isObjectLiteral)
34+
.flatMap(getStylesProperty)
35+
.flatMap(getStyleValues)
36+
.map(castToStyleLiteral);
37+
}
38+
39+
/**
40+
* Retrieves component decorators from a class.
41+
*
42+
* @param {import("ts-morph").ClassDeclaration} cls - The class declaration.
43+
* @returns {import("ts-morph").Decorator[]} An array of Component decorators.
44+
*/
45+
function getComponentDecorators(cls) {
46+
return cls.getDecorators().filter(isComponentDecorator);
3747
}
3848

3949
/**
@@ -46,6 +56,16 @@ function isComponentDecorator(decorator) {
4656
return decorator.getName() === "Component";
4757
}
4858

59+
/**
60+
* Retrieves arguments from a decorator.
61+
*
62+
* @param {import("ts-morph").Decorator} decorator - The decorator.
63+
* @returns {import("ts-morph").Node[]} An array of decorator arguments.
64+
*/
65+
function getDecoratorArguments(decorator) {
66+
return decorator.getArguments();
67+
}
68+
4969
/**
5070
* Checks if the provided expression is an object literal.
5171
*

src/parser/parser-angular.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Input } from "postcss";
2+
import { StyleParser } from "./parser-styles.js";
3+
import { Document } from "../nodes/document.js";
4+
import { parseTypescript } from "./parse-typescript.js";
5+
6+
/**
7+
* Parses the input TypeScript file to extract and process Angular component styles.
8+
*
9+
* @param {Input} input - The PostCSS `Input` object wrapping the source file.
10+
* @param {Pick<import("postcss").ProcessOptions, "from" | "map">} opts - The PostCSS processing options.
11+
* @returns {Document} The root node of the generated Abstract Syntax Tree (AST).
12+
*/
13+
export function parseAngular(input, opts) {
14+
const styleLiterals = parseTypescript(input);
15+
16+
let index = 0;
17+
const nodes = styleLiterals.map((styleLiteral, idx) => {
18+
const styleParser = new StyleParser(input, styleLiteral);
19+
const stylesRoot = styleParser.parse(opts);
20+
21+
stylesRoot.raws.codeBefore = input.css.slice(
22+
index,
23+
styleLiteral.getStart(),
24+
);
25+
26+
index = styleLiteral.getEnd();
27+
28+
// In case this is the last style node we save the rest of the file
29+
if (idx === styleLiterals.length - 1) {
30+
stylesRoot.raws.codeAfter = input.css.slice(index);
31+
}
32+
33+
return stylesRoot;
34+
});
35+
36+
const offset = input.css.length - 1;
37+
const { col: column, line } = input.fromOffset(offset);
38+
39+
return new Document({
40+
nodes,
41+
source: {
42+
input,
43+
start: { column: 1, line: 1, offset: 0 },
44+
end: {
45+
column,
46+
line,
47+
offset,
48+
},
49+
},
50+
});
51+
}

0 commit comments

Comments
 (0)