Skip to content

Commit 414b32e

Browse files
committed
feat: Basic preprocessor support.
1 parent 5f12eb5 commit 414b32e

File tree

19 files changed

+153
-73
lines changed

19 files changed

+153
-73
lines changed

packages/@css-blocks/language-server/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
"url": "https://github.com/LinkedIn/css-blocks"
1414
},
1515
"dependencies": {
16-
"@css-blocks/core": "^0.24.0",
1716
"@css-blocks/config": "^0.24.0",
17+
"@css-blocks/core": "^0.24.0",
1818
"@glimmer/syntax": "^0.42.1",
19+
"glob": "^7.1.6",
20+
"glob-escape": "^0.0.2",
1921
"opticss": "^0.6.2",
2022
"vscode-languageserver": "^5.2.1",
2123
"vscode-uri": "^2.0.3"

packages/@css-blocks/language-server/src/Server.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { search as searchForConfig } from "@css-blocks/config";
2-
import { BlockFactory, Configuration, CssBlockError, resolveConfiguration } from "@css-blocks/core";
2+
import { BlockFactory, Configuration, CssBlockError, Syntax, resolveConfiguration } from "@css-blocks/core";
33
import { CompletionItem, Definition, DidChangeConfigurationNotification, DocumentLink, DocumentLinkParams, IConnection, InitializeParams, InitializeResult, TextDocumentChangeEvent, TextDocumentPositionParams, TextDocuments } from "vscode-languageserver";
44
import { URI } from "vscode-uri";
55

@@ -9,6 +9,7 @@ import { emberDefinitionProvider } from "./definitionProviders/emberDefinitionPr
99
import { blockLinksProvider } from "./documentLinksProviders/blockLinkProvider";
1010
import { documentContentChange } from "./eventHandlers/documentContentChange";
1111
import { LSImporter } from "./Importer";
12+
import { EmberClassicTransformer } from "./pathTransformers/EmberClassicTransformer";
1213
import { PathTransformer } from "./pathTransformers/PathTransformer";
1314
import { SERVER_CAPABILITIES } from "./serverCapabilities";
1415
import { isBlockFile } from "./util/blockUtils";
@@ -18,16 +19,15 @@ import { isTemplateFile, validateTemplates } from "./util/hbsUtils";
1819
export class Server {
1920
_blockFactory: BlockFactory | undefined;
2021
_config: Readonly<Configuration> | undefined;
22+
_pathTransformer: PathTransformer | undefined;
2123
connection: IConnection;
2224
documents: TextDocuments;
23-
pathTransformer: PathTransformer;
2425
hasConfigurationCapability = false;
2526
hasWorkspaceFolderCapability = false;
2627

27-
constructor(connection: IConnection, documents: TextDocuments, pathTransformer: PathTransformer) {
28+
constructor(connection: IConnection, documents: TextDocuments) {
2829
this.connection = connection;
2930
this.documents = documents;
30-
this.pathTransformer = pathTransformer;
3131

3232
this.registerDocumentEvents();
3333
this.registerConnectionEvents();
@@ -47,6 +47,23 @@ export class Server {
4747
return this._blockFactory;
4848
}
4949

50+
get pathTransformer(): PathTransformer {
51+
if (!this._pathTransformer) {
52+
let syntaxes = new Array<Syntax>();
53+
let keys = Object.keys(this.config.preprocessors);
54+
for (let k of keys) {
55+
if (Syntax[k]) {
56+
syntaxes.push(Syntax[k]);
57+
}
58+
}
59+
if (!syntaxes.includes(Syntax.css)) {
60+
syntaxes.push(Syntax.css);
61+
}
62+
this._pathTransformer = new EmberClassicTransformer(syntaxes);
63+
}
64+
return this._pathTransformer;
65+
}
66+
5067
listen() {
5168
this.documents.listen(this.connection);
5269
this.connection.listen();
@@ -61,7 +78,7 @@ export class Server {
6178
async onDidChangeContent(e: TextDocumentChangeEvent) {
6279
// only track incremental changes within block files
6380
this.blockFactory.reset();
64-
if (isBlockFile(e.document.uri)) {
81+
if (isBlockFile(e.document.uri, this.config)) {
6582
const cssBlockErrors = await documentContentChange(e, this.blockFactory);
6683
this.sendDiagnostics(cssBlockErrors, e.document.uri);
6784

@@ -95,7 +112,7 @@ export class Server {
95112
});
96113

97114
this.connection.onDocumentLinks(async (params: DocumentLinkParams): Promise<DocumentLink[]> => {
98-
return await blockLinksProvider(this.documents, params);
115+
return await blockLinksProvider(this.documents, params, this.config);
99116
});
100117
}
101118

@@ -126,6 +143,8 @@ export class Server {
126143
}
127144
options = result || (rootDir ? {rootDir} : {});
128145
options.importer = new LSImporter(this.documents, options.importer);
146+
// We set both of these explicitly here just in case they were accessed
147+
// before initialization.
129148
this._config = resolveConfiguration(options);
130149
this._blockFactory = createBlockFactory(this._config);
131150

packages/@css-blocks/language-server/src/completionProviders/emberCompletionProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BlockFactory } from "@css-blocks/core/dist/src";
1+
import { BlockFactory } from "@css-blocks/core";
22
import { CompletionItem, TextDocumentPositionParams, TextDocuments } from "vscode-languageserver";
33

44
import { PathTransformer } from "../pathTransformers/PathTransformer";
@@ -15,7 +15,7 @@ export async function emberCompletionProvider(documents: TextDocuments, factory:
1515

1616
if (isTemplateFile(document.uri)) {
1717
return await getHbsCompletions(document, params.position, factory, pathTransformer);
18-
} else if (isBlockFile(document.uri)) {
18+
} else if (isBlockFile(document.uri, factory.configuration)) {
1919
return await getBlockCompletions(document, params.position);
2020
} else {
2121
return [];

packages/@css-blocks/language-server/src/createBlockFactory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BlockFactory, Options } from "@css-blocks/core/dist/src";
1+
import { BlockFactory, Options } from "@css-blocks/core";
22
import { postcss } from "opticss";
33

44
export function createBlockFactory(config: Options) {

packages/@css-blocks/language-server/src/definitionProviders/emberDefinitionProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BlockFactory } from "@css-blocks/core/dist/src";
1+
import { BlockFactory } from "@css-blocks/core";
22
import { Definition, TextDocumentPositionParams, TextDocuments } from "vscode-languageserver";
33

44
import { PathTransformer } from "../pathTransformers/PathTransformer";

packages/@css-blocks/language-server/src/documentLinksProviders/blockLinkProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Configuration } from "@css-blocks/core";
12
import * as path from "path";
23
import { DocumentLinkParams, TextDocuments } from "vscode-languageserver";
34
import { DocumentLink } from "vscode-languageserver-types";
@@ -7,10 +8,10 @@ import { isBlockFile } from "../util/blockUtils";
78

89
const LINK_REGEX = /from\s+(['"])([^'"]+)\1;/;
910

10-
export async function blockLinksProvider(documents: TextDocuments, params: DocumentLinkParams): Promise<DocumentLink[]> {
11+
export async function blockLinksProvider(documents: TextDocuments, params: DocumentLinkParams, config: Readonly<Configuration>): Promise<DocumentLink[]> {
1112
let { uri } = params.textDocument;
1213

13-
if (!isBlockFile(uri)) {
14+
if (!isBlockFile(uri, config)) {
1415
return [];
1516
}
1617

packages/@css-blocks/language-server/src/eventHandlers/documentContentChange.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BlockFactory, CssBlockError } from "@css-blocks/core/dist/src";
1+
import { BlockFactory, CssBlockError } from "@css-blocks/core";
22
import { TextDocumentChangeEvent } from "vscode-languageserver";
33
import { URI } from "vscode-uri";
44

@@ -7,7 +7,7 @@ import { isBlockFile } from "../util/blockUtils";
77
export async function documentContentChange(e: TextDocumentChangeEvent, blockFactory: BlockFactory): Promise<CssBlockError[]> {
88
const { uri } = e.document;
99

10-
if (isBlockFile(uri)) {
10+
if (isBlockFile(uri, blockFactory.configuration)) {
1111
try {
1212
// parses the block file to get the block and errors if there's a problem
1313
// along the way. The importer ensures that we're getting live contents if
Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,60 @@
1-
import { Syntax } from "@css-blocks/core/dist/src";
1+
import { Syntax } from "@css-blocks/core";
2+
import { existsSync } from "fs";
3+
import * as glob from "glob";
4+
import * as globEscape from "glob-escape";
25
import * as path from "path";
36

47
import { PathTransformer } from "./PathTransformer";
58

9+
const TEMPLATES_DIR_RE = new RegExp(`${path.sep}templates${path.sep}`);
10+
const STYLES_DIR_RE = new RegExp(`${path.sep}styles${path.sep}`);
11+
612
export class EmberClassicTransformer implements PathTransformer {
7-
_syntax: Syntax;
13+
_syntaxes: Array<Syntax>;
814
_templateExtension = "hbs";
15+
_allowsAnySyntax: boolean;
16+
17+
constructor(syntaxes: Array<Syntax>) {
18+
this._syntaxes = syntaxes.filter(s => s !== Syntax.other);
19+
this._allowsAnySyntax = syntaxes.includes(Syntax.other);
20+
}
921

10-
// TODO: Accept an array of syntaxes that are set up in the preprocessor configuration.
11-
constructor(syntax: Syntax) {
12-
this._syntax = syntax;
22+
_blockSyntaxSupported(extension: string): boolean {
23+
if (this._allowsAnySyntax || extension === "css") {
24+
return true;
25+
} else {
26+
return !!this._syntaxes.find(s => s === extension);
27+
}
1328
}
1429

15-
templateToBlock(templatePath: string): string {
16-
return templatePath
17-
.replace(/.hbs$/, `.block.${this._syntax}`)
18-
.replace(
19-
new RegExp(`${path.sep}templates${path.sep}`),
20-
`${path.sep}styles${path.sep}`,
21-
);
30+
templateToBlock(templatePath: string): string | null {
31+
let pathObj = path.parse(templatePath.replace(TEMPLATES_DIR_RE, `${path.sep}styles${path.sep}`));
32+
let dir = pathObj.dir;
33+
let filename = pathObj.name;
34+
let pattern = `${globEscape(filename)}.block.*`;
35+
let files = glob.sync(pattern, {cwd: dir});
36+
for (let file of files) {
37+
let ext = path.extname(file).substring(1);
38+
if (this._blockSyntaxSupported(ext)) {
39+
return path.join(dir, file);
40+
}
41+
}
42+
return null;
2243
}
2344

24-
blockToTemplate(blockPath: string): string {
25-
return blockPath
26-
.replace(new RegExp(`\.block\.${this._syntax}$`), `.${this._templateExtension}`)
27-
.replace(
28-
new RegExp(`${path.sep}styles${path.sep}`),
29-
`${path.sep}templates${path.sep}`,
30-
);
45+
blockToTemplate(blockPath: string): string | null {
46+
let pathObj = path.parse(blockPath);
47+
delete pathObj.base;
48+
pathObj.ext = `.${this._templateExtension}`;
49+
if (pathObj.name.endsWith(".block")) {
50+
pathObj.name = pathObj.name.substring(0, pathObj.name.length - 6);
51+
}
52+
pathObj.dir = pathObj.dir.replace(STYLES_DIR_RE, `${path.sep}templates${path.sep}`);
53+
let templatePath = path.format(pathObj);
54+
if (existsSync(templatePath)) {
55+
return templatePath;
56+
} else {
57+
return null;
58+
}
3159
}
3260
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import { Syntax } from "@css-blocks/core/dist/src";
2-
31
export interface PathTransformer {
4-
_syntax: Syntax;
5-
templateToBlock(templatePath: string): string;
6-
blockToTemplate(blockPath: string): string;
2+
templateToBlock(templatePath: string): string | null;
3+
blockToTemplate(blockPath: string): string | null;
74
}
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
import { Syntax } from "@css-blocks/core";
21
import { ProposedFeatures, TextDocuments, createConnection } from "vscode-languageserver";
32

4-
import { EmberClassicTransformer } from "./pathTransformers/EmberClassicTransformer";
53
import { Server } from "./Server";
64

7-
// TODO: We will eventually need to support different path transformations
8-
// and block syntax depending on configuration. For now we are just assuming
9-
// an ember classic project and css syntax.
10-
const pathTransformer = new EmberClassicTransformer(Syntax.css);
115
const connection = createConnection(ProposedFeatures.all);
126
const documents = new TextDocuments();
137

14-
let server = new Server(connection, documents, pathTransformer);
8+
let server = new Server(connection, documents);
159

1610
server.listen();

0 commit comments

Comments
 (0)