feat(css-parser): `@import`
ADD
internal/ast/css/import/CSSAtImport.ts
+import {CSSAtImportValue, NodeBaseWithComments} from "@internal/ast";
+import {createBuilder} from "../../utils";
+
+export interface CSSAtImport extends NodeBaseWithComments {
+ readonly type: "CSSAtImport";
+ readonly value: CSSAtImportValue;
+}
+
+export const cssAtImport = createBuilder<CSSAtImport>(
+ "CSSAtImport",
+ {
+ bindingKeys: {},
+ visitorKeys: {
+ value: true,
+ },
+ },
+);

MODIFY
internal/ast/css/unions.ts
internal/ast/css/unions.ts
import * as n from "@internal/ast";
import {
+ CSSAtImport,
CSSAtPage,
CSSAtRule,
CSSBlock,
@@ -65,6 +66,7 @@ export type AnyCSSValue =
| CSSMinFunction
| CSSMediaQueryList
| CSSSupportsCondition
+ | CSSAtImport
| CSSRaw;
export type RangeNameAndValue = [
@@ -97,7 +99,10 @@ export type CSSAtRuleValue =
| CSSKeyframe
| CSSMediaQueryList
| CSSAtPage
- | CSSFontFace;
+ | CSSFontFace
+ | CSSAtImport;
+
+export type CSSAtImportValue = CSSString | CSSUrlFunction;
export type CSSBlockValue = Array<
AnyCSSValue | CSSRule | CSSAtRule | CSSDeclaration

MODIFY
internal/ast/index.ts
internal/ast/index.ts
@@ -12,9 +12,10 @@ export * from "./unions";
export {bindingKeys, nodeNames, visitorKeys} from "./utils";
export type AnyNodes = AnyNode | (AnyNode[]);
-/* GENERATED:START(hash:38a1e70803d1c52bc02689d26324b927e581a59a,id:main) Everything below is automatically generated. DO NOT MODIFY. Run `./rome run scripts/generated-files/ast` to update. */
+/* GENERATED:START(hash:3208e422bbfac2f064518f78e313f58a7e30f258,id:main) Everything below is automatically generated. DO NOT MODIFY. Run `./rome run scripts/generated-files/ast` to update. */
export * from "./common/comments/CommentBlock";
export * from "./common/comments/CommentLine";
+export * from "./css/import/CSSAtImport";
export * from "./css/page/CSSAtPage";
export * from "./css/core/CSSAtRule";
export * from "./css/selectors/CSSAttributeSelector";
@@ -323,6 +324,7 @@ export * from "./js/typescript/TSVoidKeywordTypeAnnotation";
export type AnyNode =
| n.CommentBlock
| n.CommentLine
+ | n.CSSAtImport
| n.CSSAtPage
| n.CSSAtRule
| n.CSSAttributeSelector

ADD
internal/css-parser/parser/at-import.ts
+// https://www.w3.org/TR/css-cascade-4/#conditional-import
+import {CSSParser} from "@internal/css-parser/types";
+import {CSSAtImport, CSSAtImportValue} from "@internal/ast";
+import {matchToken, nextToken, readToken} from "@internal/css-parser/tokenizer";
+import {descriptions} from "@internal/diagnostics";
+import {parseFunction} from "@internal/css-parser/parser/function";
+
+export function parseAtImport(parser: CSSParser): CSSAtImport | undefined {
+ const start = parser.getPosition();
+ let value: CSSAtImportValue | undefined = undefined;
+ while (matchToken(parser, "Whitespace")) {
+ readToken(parser, "Whitespace");
+ }
+ const token = parser.getToken();
+ let isFunctionToken = false;
+
+ if (token.type === "String") {
+ const functionStart = parser.getPosition();
+ nextToken(parser);
+ value = parser.finishNode(
+ functionStart,
+ {
+ type: "CSSString",
+ value: token.value,
+ },
+ );
+ } else if (token.type === "Function") {
+ const urlFunction = parseFunction(parser);
+ if (urlFunction?.type === "CSSUrlFunction") {
+ value = urlFunction;
+ }
+
+ isFunctionToken = true;
+ }
+
+ if (value) {
+ if (parser.getToken().type === "RightParen") {
+ nextToken(parser);
+ }
+ // Semi colon is optional, but if present we have to move forward in order to not
+ // break the existing usage and make it as part of the current node
+ if (parser.getToken().type === "Semi") {
+ nextToken(parser);
+ } else {
+ if (isFunctionToken) {
+ parser.unexpectedDiagnostic({
+ description: descriptions.CSS_PARSER.UNTERMINATED_FUNCTION,
+ token,
+ });
+ return undefined;
+ }
+ }
+ return parser.finishNode(
+ start,
+ {
+ type: "CSSAtImport",
+ value,
+ },
+ );
+ }
+ parser.unexpectedDiagnostic({
+ description: descriptions.CSS_PARSER.AT_IMPORT_INVALID_ARGUMENT,
+ token,
+ });
+ return undefined;
+}

MODIFY
internal/css-parser/parser/rules.ts
internal/css-parser/parser/rules.ts
@@ -14,6 +14,7 @@ import {parseMediaList} from "@internal/css-parser/parser/media";
import {parseAtSupports} from "@internal/css-parser/parser/supports";
import {parseFontFace} from "@internal/css-parser/parser/font";
import {parseAtPage} from "@internal/css-parser/parser/page";
+import {parseAtImport} from "@internal/css-parser/parser/at-import";
export function parseRules(
parser: CSSParser,
@@ -124,6 +125,11 @@ export function parseAtRule(
break;
}
+ if (previousToken.value === "import") {
+ block = parseAtImport(parser);
+ break;
+ }
+
if (previousToken.value === "supports") {
const value = parseAtSupports(parser);
if (value) {

MODIFY
internal/css-parser/parser/selectors.ts
internal/css-parser/parser/selectors.ts
@@ -390,6 +390,7 @@ function parseSelector(parser: CSSParser): CSSSelector {
patterns.push(selector);
}
+ console.log(parser.getToken());
if (
!(selector ||
combinator ||

ADD
internal/css-parser/test-fixtures/import/input.css
+@import "something.css";
+@import url("something.css");

ADD
internal/css-parser/test-fixtures/import/input.test.md
+# `index.test.ts`
+
+**DO NOT MODIFY**. This file has been autogenerated. Run `rome test internal/css-parser/index.test.ts --update-snapshots` to update.
+
+## `import`
+
+```javascript
+CSSRoot {
+ body: [
+ CSSAtRule {
+ name: "import"
+ prelude: []
+ block: CSSAtImport {
+ value: CSSString {
+ value: "something.css"
+ loc: SourceLocation import/input.css 1:8-1:23
+ }
+ loc: SourceLocation import/input.css 1:7-1:24
+ }
+ loc: SourceLocation import/input.css 1:0-1:24
+ }
+ CSSAtRule {
+ name: "import"
+ prelude: []
+ block: CSSAtImport {
+ value: CSSUrlFunction {
+ name: "url"
+ params: [
+ CSSString {
+ value: "something.css"
+ loc: SourceLocation import/input.css 2:12-2:27
+ }
+ ]
+ loc: SourceLocation import/input.css 2:8-2:28
+ }
+ loc: SourceLocation import/input.css 2:7-2:29
+ }
+ loc: SourceLocation import/input.css 2:0-2:29
+ }
+ ]
+ comments: []
+ corrupt: false
+ diagnostics: []
+ path: RelativePath<import/input.css>
+ loc: SourceLocation import/input.css 1:0-2:29
+}
+```

MODIFY
internal/diagnostics/descriptions/parsers/cssParser.ts
internal/diagnostics/descriptions/parsers/cssParser.ts
@@ -201,4 +201,8 @@ export const cssParser = createDiagnosticsCategory({
AT_FONT_FACE_MISSING_SRC: {
message: markup`The rule <emphasis>@font-face</emphasis> needs the property <emphasis>src</emphasis> in order to be valid.`,
},
+
+ AT_IMPORT_INVALID_ARGUMENT: {
+ message: markup`Unexpected argument in at-import`,
+ },
});

ADD
internal/formatter/builders/css/import/CSSAtImport.ts
+import {CSSAtImport} from "@internal/ast";
+import {Builder, Token, concat} from "@internal/formatter";
+
+export default function CSSAtImport(builder: Builder, node: CSSAtImport): Token {
+ return concat([builder.tokenize(node.value, node), ";"]);
+}

MODIFY
internal/formatter/builders/index.ts
internal/formatter/builders/index.ts
@@ -14,11 +14,13 @@ const builders: ExtendedMap<string, BuilderMethod<any>> = new ExtendedMap(
);
export default builders;
-/* GENERATED:START(hash:189e82475293dc06ac237f85e5355a84d8792ba1,id:main) Everything below is automatically generated. DO NOT MODIFY. Run `./rome run scripts/generated-files/ast` to update. */
+/* GENERATED:START(hash:a80f93124590581e9bda4307796efdcd8f0a6a9b,id:main) Everything below is automatically generated. DO NOT MODIFY. Run `./rome run scripts/generated-files/ast` to update. */
import CommentBlock from "./common/comments/CommentBlock";
builders.set("CommentBlock", CommentBlock);
import CommentLine from "./common/comments/CommentLine";
builders.set("CommentLine", CommentLine);
+import CSSAtImport from "./css/import/CSSAtImport";
+builders.set("CSSAtImport", CSSAtImport);
import CSSAtPage from "./css/page/CSSAtPage";
builders.set("CSSAtPage", CSSAtPage);
import CSSAtRule from "./css/core/CSSAtRule";

ADD
internal/formatter/test-fixtures/css/at-import/input.css
+@import "something.css";
+@import url("something.css");

ADD
internal/formatter/test-fixtures/css/at-import/input.test.md
+# `index.test.ts`
+
+**DO NOT MODIFY**. This file has been autogenerated. Run `rome test internal/formatter/index.test.ts --update-snapshots` to update.
+
+## `css > at-import`
+
+### `Diagnostics`
+
+```
+
+```
+
+### `Input`
+
+```css
+@import "something.css";
+@import url("something.css");
+
+```
+
+### `Output`
+
+```css
+@import "something.css";
+
+@import url("something.css");
+
+
+```

feat(css-parser): `@import` (#1536) (#1564)

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: ktfth <44123854+ktfth@users.noreply.github.com>