Skip to content

Commit

Permalink
function-no-unknown: add support for @use (#773)
Browse files Browse the repository at this point in the history
* function-no-unknown: add support for @use

* Additional test case
  • Loading branch information
kristerkari committed Mar 14, 2023
1 parent 5cce237 commit 2b31246
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
111 changes: 111 additions & 0 deletions src/rules/function-no-unknown/__tests__/index.js
Expand Up @@ -23,6 +23,78 @@ testRule({
},
{
code: "a { color: color.adjust(#6b717f, $red: 15); }"
},
{
code: `
@use 'mymodule';
.foobar {
property: mymodule.myfunction();
}
`,
description: "@use namespaced function. issue #760"
},
{
code: `
@use "mymodule";
.foobar {
property: mymodule.myfunction();
}
`,
description: "@use namespaced function. issue #760"
},
{
code: `
@use "src/mymodule";
.foobar {
property: mymodule.myfunction();
}
`,
description:
"@use namespaced function (By default, the namespace is just the last component of the module's URL.) issue #760"
},
{
code: `
@use "src/mymodule" as m;
.foobar {
property: m.myfunction();
}
`,
description: "@use namespaced function, 'as' keyword. issue #760"
},
{
code: `
@use 'library' with (
$black: #222,
$border-radius: 0.1rem
);
.foobar {
property: library.fn();
}
`,
description: "@use namespaced function, 'with' keyword. issue #760"
},
{
code: `
@use 'sass:math';
$half: math.percentage(1/2);
`,
description: "@use built-in function."
},
{
code: `
@use 'sass:map';
@use 'sass:string';
$map-get: map.get(('key': 'value'), 'key');
$str-index: string.index('string', 'i');
`,
description: "@use built-in function."
}
],

Expand All @@ -38,6 +110,45 @@ testRule({
message: messages.rejected("color.unknown"),
line: 1,
column: 12
},
{
code: `
@use 'mymodule';
.foobar {
property: othermodule.myfunction();
}
`,
message: messages.rejected("othermodule.myfunction"),
line: 5,
column: 19,
description: "non-matching @use namespace"
},
{
code: `
@use "mymodule" as m;
.foobar {
property: c.myfunction();
}
`,
message: messages.rejected("c.myfunction"),
line: 5,
column: 19,
description: "non-matching @use namespace, 'as' keyword"
},
{
code: `
@use 'something' as *
.class {
color: myFn();
}
`,
message: messages.rejected("myFn"),
line: 5,
column: 16,
description: "@use without a namespace"
}
]
});
Expand Down
42 changes: 42 additions & 0 deletions src/rules/function-no-unknown/index.js
Expand Up @@ -19,6 +19,32 @@ export const meta = {
url: ruleUrl(ruleName)
};

function isNamespacedFunction(fn) {
const namespacedFunc = /^\w+\.\w+$/;
return namespacedFunc.test(fn);
}

function isAtUseAsSyntax(nodes) {
const [first, second, third] = nodes.slice(-3);
return (
first.type === "word" &&
first.value === "as" &&
second.type === "space" &&
third.type === "word"
);
}

function getAtUseNamespace(nodes) {
if (isAtUseAsSyntax(nodes)) {
const [last] = nodes.slice(-1);
return last.value;
}
const [first] = nodes;
const parts = first.value.split("/");
const [last] = parts.slice(-1);
return last;
}

export default function rule(primaryOption, secondaryOptions) {
return (root, result) => {
const validOptions = utils.validateOptions(
Expand Down Expand Up @@ -65,6 +91,22 @@ export default function rule(primaryOption, secondaryOptions) {
return;
}

if (isNamespacedFunction(funcName)) {
const atUseNamespaces = [];

root.walkAtRules(/^use$/i, atRule => {
const { nodes } = valueParser(atRule.params);
atUseNamespaces.push(getAtUseNamespace(nodes));
});

if (atUseNamespaces.length) {
const [namespace] = funcName.split(".");
if (atUseNamespaces.includes(namespace)) {
return;
}
}
}

if (!ignoreFunctionsAsSet.has(funcName)) {
utils.report({
message: messages.rejected(funcName),
Expand Down

0 comments on commit 2b31246

Please sign in to comment.