Skip to content

Commit 79fafe8

Browse files
committed
feat: Imports via npm and aliases.
1 parent 7b945a1 commit 79fafe8

File tree

9 files changed

+100
-10
lines changed

9 files changed

+100
-10
lines changed

packages/@css-blocks/cli/README.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# CSS Blocks Command Line Interface
22

3-
The css-blocks Rewriter and Analyzer for Glimmer templates.
3+
A simple interface for working with CSS Blocks.
4+
Not meant to replace a proper build tool integration.
45

56
## Installation
67

@@ -17,14 +18,16 @@ npx @css-blocks/cli validate blocks/*.block.css
1718
## Usage
1819

1920
```
20-
css-blocks <cmd> [options] <blocks..>
21+
css-blocks <cmd> [options] block-dir-or-file...
2122
2223
Commands:
2324
css-blocks validate <blocks..> Validate block file syntax.
2425
2526
Options:
26-
--version Show version number [boolean]
27-
--preprocessors A JS file that exports an object that maps extensions to a
28-
preprocessor function for that type. [string]
29-
--help Show help [boolean]
27+
--version Show version number
28+
--preprocessors A JS file that exports an object that maps extensions to a preprocessor function for that type.
29+
--npm Allow importing from node_modules
30+
--alias Define an import alias. Requires two arguments: an alias and a directory.
31+
--help Show help
32+
3033
```

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

+42-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import { BlockFactory, CssBlockError, Preprocessors } from "@css-blocks/core";
1+
import { BlockFactory, CssBlockError, Importer, NodeJsImporter, Preprocessors } from "@css-blocks/core";
22
import chalk = require("chalk");
33
import fse = require("fs-extra");
44
import path = require("path");
55
import yargs = require("yargs");
66

7+
type Aliases = ConstructorParameters<typeof NodeJsImporter>[0];
8+
79
/**
810
* Typecast for result of command line argument parsing.
911
*/
1012
interface GlobalArgs {
1113
preprocessors: string | undefined;
14+
alias: Array<string | number> | undefined;
15+
npm: boolean | undefined;
1216
[k: string]: unknown;
1317
}
1418

@@ -24,6 +28,8 @@ interface ValidateOptions {
2428
* A path to the preprocessors code.
2529
*/
2630
preprocessors?: string;
31+
alias?: Array<string | number>;
32+
npm?: boolean;
2733
}
2834

2935
export class CLI {
@@ -64,19 +70,35 @@ export class CLI {
6470
description: "A JS file that exports an object that maps extensions to a preprocessor function for that type.",
6571
nargs: 1,
6672
})
73+
.option("npm", {
74+
type: "boolean",
75+
global: true,
76+
description: "Allow importing from node_modules",
77+
nargs: 0,
78+
})
79+
.option("alias", {
80+
type: "array",
81+
global: true,
82+
description: "Define an import alias. Requires two arguments: an alias and a directory.",
83+
implies: "npm",
84+
nargs: 2,
85+
})
6786
.command<ValidateArgs>(
6887
"validate <blocks..>",
6988
"Validate block file syntax.", (y) =>
7089
y.positional("blocks", {
7190
description: "files or directories containing css blocks.",
7291
}),
7392
(argv: ValidateArgs) => {
74-
let { preprocessors } = argv;
93+
let { preprocessors, alias, npm } = argv;
7594
argv.promise = this.validate(argv.blocks as Array<string>, {
7695
preprocessors,
96+
alias,
97+
npm,
7798
});
7899
},
79100
)
101+
.wrap(yargs.terminalWidth())
80102
.demandCommand(1, "No command was provided.")
81103
.help();
82104
}
@@ -86,11 +108,27 @@ export class CLI {
86108
*/
87109
async validate(blockFiles: Array<string>, options: ValidateOptions) {
88110
let preprocessors: Preprocessors = options.preprocessors ? require(path.resolve(options.preprocessors)) : {};
89-
let factory = new BlockFactory({preprocessors});
111+
let npm = options.npm || false;
112+
let aliases: Aliases = [];
113+
let aliasList = options.alias || [];
114+
for (let i = 0; i < aliasList.length; i = i + 2) {
115+
let alias = aliasList[i].toString();
116+
let dir = path.resolve(aliasList[i + 1].toString());
117+
aliases.push({alias, path: dir});
118+
}
119+
let importer: Importer | undefined;
120+
if (npm) {
121+
importer = new NodeJsImporter(aliases);
122+
}
123+
let factory = new BlockFactory({preprocessors, importer});
90124
let errorCount = 0;
91125
for (let blockFile of blockFiles) {
92126
try {
93-
await factory.getBlockFromPath(path.resolve(blockFile));
127+
if (importer) {
128+
let ident = importer.identifier(null, blockFile, factory.configuration);
129+
blockFile = importer.filesystemPath(ident, factory.configuration) || blockFile;
130+
}
131+
await factory.getBlockFromPath(blockFile);
94132
// if the above line doesn't throw then there wasn't a syntax error.
95133
this.println(`${this.chalk.green("ok")}\t${path.relative(process.cwd(), path.resolve(blockFile))}`);
96134
} catch (e) {

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

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert = require("assert");
22
import path = require("path");
3+
import { chdir, cwd } from "process";
34

45
import { TestCLI as CLI } from "./TestCLI";
56

@@ -14,7 +15,11 @@ function distFile(...relativePathSegments: Array<string>): string {
1415
return path.resolve(__dirname, "..", ...relativePathSegments);
1516
}
1617

18+
const WORKING_DIR = cwd();
1719
describe("validate", () => {
20+
afterEach(() => {
21+
chdir(WORKING_DIR);
22+
});
1823
it("can check syntax for a valid block file", async () => {
1924
let cli = new CLI();
2025
await cli.run(["validate", fixture("basic/simple.block.css")]);
@@ -33,6 +38,20 @@ describe("validate", () => {
3338
assert.equal(cli.output, `error\t${relFixture("basic/error.block.css")}:1:5 Two distinct classes cannot be selected on the same element: .foo.bar\n`);
3439
assert.equal(cli.exitCode, 1);
3540
});
41+
it("can import from node_modules", async () => {
42+
chdir(fixture("importing"));
43+
let cli = new CLI();
44+
await cli.run(["validate", "--npm", "npm.block.css"]);
45+
assert.equal(cli.output, `ok\tnpm.block.css\n`);
46+
assert.equal(cli.exitCode, 0);
47+
});
48+
it("can import with aliases", async () => {
49+
chdir(fixture("importing"));
50+
let cli = new CLI();
51+
await cli.run(["validate", "--npm", "--alias", "basic", "../basic", "alias.block.css"]);
52+
assert.equal(cli.output, `ok\talias.block.css\n`);
53+
assert.equal(cli.exitCode, 0);
54+
});
3655
});
3756

3857
describe("validate with preprocessors", () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!node_modules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@block red from "basic/simple.block.css";
2+
3+
:scope {
4+
font-family: resolve("red");
5+
color: blue;
6+
}

packages/@css-blocks/cli/test/fixtures/importing/node_modules/block-module/blocks/font.block.css

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@css-blocks/cli/test/fixtures/importing/node_modules/block-module/index.block.css

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@css-blocks/cli/test/fixtures/importing/node_modules/block-module/package.json

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@block font from "block-module";
2+
3+
:scope {
4+
font-family: resolve("font");
5+
font-family: serif;
6+
}

0 commit comments

Comments
 (0)