Skip to content

Commit 190993f

Browse files
committed
feat: Display block import references in error output.
Closes #248.
1 parent 7e030fb commit 190993f

File tree

6 files changed

+26
-3
lines changed

6 files changed

+26
-3
lines changed

packages/@css-blocks/cli/src/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ export class CLI {
173173
if (!errorHasRange(loc)) return;
174174
let filename = path.relative(process.cwd(), path.resolve(loc && loc.filename || blockFileRelative));
175175
this.println("\t" + this.chalk.bold.redBright(e.origMessage));
176+
for (let referenceLocation of e.importStack.reverse()) {
177+
if (referenceLocation.filename) {
178+
referenceLocation.filename = path.relative(process.cwd(), path.resolve(referenceLocation.filename));
179+
}
180+
this.println(
181+
this.chalk.bold.white("\tIn block referenced at"),
182+
this.chalk.bold.whiteBright(charInFile(referenceLocation)),
183+
);
184+
}
176185
if (hasMappedPosition(loc)) {
177186
this.println(
178187
this.chalk.bold.white("\tAt compiled output of"),

packages/@css-blocks/cli/test/cli-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Found 1 error in 1 file.
4545
assert.equal(cli.output,
4646
`error\t${relFixture("basic/transitive-error.block.css")}
4747
\tTwo distinct classes cannot be selected on the same element: .foo.bar
48+
\tIn block referenced at test/fixtures/basic/transitive-error.block.css:1:1
4849
\tAt ${relFixture("basic/error.block.css")}:1:5
4950
\t1: .foo.bar {
5051
\t2: color: red;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@block error from "./transitive-error.block.css";
2+
3+
:scope {
4+
extends: error;
5+
}

packages/@css-blocks/core/src/BlockParser/features/import-blocks.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,17 @@ export async function importBlocks(block: Block, factory: BlockFactory, file: st
4444
// Import file, then parse file, then save block reference.
4545
let blockPromise: Promise<Block> = factory.getBlockRelative(block.identifier, blockPath);
4646

47-
// Validate our imported block name is a valid CSS identifier.
47+
blockPromise = blockPromise.catch((e) => {
48+
if (e instanceof errors.CssBlockError) {
49+
e.importStack.push(sourceRange(factory.configuration, block.stylesheet, file, atRule));
50+
}
51+
throw e;
52+
});
53+
4854
let blockNames = parseBlockNames(blockList, true);
4955
for (let localName of Object.keys(blockNames)) {
5056
let remoteName = blockNames[localName];
57+
// Validate our imported block name is a valid CSS identifier.
5158
if (!CLASS_NAME_IDENT.test(localName)) {
5259
throw new errors.InvalidBlockSyntax(
5360
`Illegal block name in import. "${localName}" is not a legal CSS identifier.`,
@@ -104,5 +111,4 @@ export async function importBlocks(block: Block, factory: BlockFactory, file: st
104111
}
105112
});
106113
return block;
107-
108114
}

packages/@css-blocks/core/src/SourceLocation.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function addSourcePositions(...locations: SourcePosition[]) {
7777
* @param node The PostCSS Node object in question.
7878
* @returns An object representing the filename, line number and column number.
7979
*/
80-
export function sourceRange(configuration: Configuration, root: postcss.Root | null | undefined, filename: string, node: postcss.Node): SourceRange | SourceFile {
80+
export function sourceRange(configuration: Configuration, root: postcss.Root | null | undefined, filename: string, node: postcss.Node): MappedSourceRange | SourceRange | SourceFile {
8181
if (node.source && node.source.start && node.source.end) {
8282
let {start, end} = node.source;
8383
return sourceOrSourceMappedRange(configuration, root, filename, start, end);

packages/@css-blocks/core/src/errors.ts

+2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ interface HasPrefix {
2626
export class CssBlockError extends Error {
2727
static prefix = "Error";
2828
origMessage: string;
29+
importStack: Array<SourceLocation.SourceRange | SourceLocation.MappedSourceRange | SourceLocation.SourceFile>;
2930
private _location?: ErrorLocation;
3031
constructor(message: string, location?: ErrorLocation) {
3132
super(message);
3233
this.origMessage = message;
3334
this._location = location;
35+
this.importStack = new Array();
3436
super.message = this.annotatedMessage();
3537
}
3638

0 commit comments

Comments
 (0)