Repository: stylelint-scss/stylelint-scss
Pull request #780 (2023-03-13 16:58:30)

build(deps-dev): bump rimraf from 4.3.1 to 4.4.0
Bumps [rimraf](https://github.com/isaacs/rimraf) from 4.3.1 to 4.4.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/isaacs/rimraf/blob/main/CHANGELOG.md">rimraf's changelog</a>.</em></p>
<blockquote>
<h1>4.4</h1>
<ul>
<li>Provide Dirent or Stats object as second argument to filter</li>
</ul>
<h1>4.3</h1>
<ul>
<li>Return boolean indicating whether the path was fully removed</li>
<li>Add filter option</li>
<li>bin: add --verbose, -v to print files as they are deleted</li>
<li>bin: add --no-verbose, -V to not print files as they are deleted</li>
<li>bin: add -i --interactive to be prompted on each deletion</li>
<li>bin: add -I --no-interactive to not be prompted on each
deletion</li>
<li><strong>4.3.1</strong> Fixed inappropriately following symbolic links to
directories</li>
</ul>
<h1>v4.2</h1>
<ul>
<li>Brought back <code>glob</code> support, using the new and improved glob v9</li>
</ul>
<h1>v4.1</h1>
<ul>
<li>Improved hybrid module with no need to look at the <code>.default</code>
dangly bit. <code>.default</code> preserved as a reference to <code>rimraf</code>
for compatibility with anyone who came to rely on it in v4.0.</li>
<li>Accept and ignore <code>-rf</code> and <code>-fr</code> arguments to the bin.</li>
</ul>
<h1>v4.0</h1>
<ul>
<li>Remove <code>glob</code> dependency entirely. This library now only
accepts actual file and folder names to delete.</li>
<li>Accept array of paths or single path.</li>
<li>Windows performance and reliability improved.</li>
<li>All strategies separated into explicitly exported methods.</li>
<li>Drop support for Node.js below version 14</li>
<li>rewrite in TypeScript</li>
<li>ship CJS/ESM hybrid module</li>
<li>Error on unknown arguments to the bin. (Previously they were
silently ignored.)</li>
</ul>
<h1>v3.0</h1>
<ul>
<li>Add <code>--preserve-root</code> option to executable (default true)</li>
<li>Drop support for Node.js below version 6</li>
</ul>
<h1>v2.7</h1>
<ul>
<li>Make <code>glob</code> an optional dependency</li>
</ul>
<h1>2.6</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/isaacs/rimraf/commit/cd0b6f485b6334fb7ee45d3af716be7105293296"><code>cd0b6f4</code></a> 4.4.0</li>
<li><a href="https://github.com/isaacs/rimraf/commit/bc6c09afb8c6cf0df336729ad700c64912122cef"><code>bc6c09a</code></a> provide dirent/stats as second arg to filter method</li>
<li>See full diff in <a href="https://github.com/isaacs/rimraf/compare/v4.3.1...v4.4.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rimraf&package-manager=npm_and_yarn&previous-version=4.3.1&new-version=4.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/package-lock.json b/package-lock.json
index 6281fc2..b0fc203 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10860,9 +10860,9 @@
       "dev": true
     },
     "node_modules/rimraf": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.3.1.tgz",
-      "integrity": "sha512-GfHJHBzFQra23IxDzIdBqhOWfbtdgS1/dCHrDy+yvhpoJY5TdwdT28oWaHWfRpKFDLd3GZnGTx6Mlt4+anbsxQ==",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz",
+      "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==",
       "dev": true,
       "dependencies": {
         "glob": "^9.2.0"
@@ -20140,9 +20140,9 @@
       "dev": true
     },
     "rimraf": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.3.1.tgz",
-      "integrity": "sha512-GfHJHBzFQra23IxDzIdBqhOWfbtdgS1/dCHrDy+yvhpoJY5TdwdT28oWaHWfRpKFDLd3GZnGTx6Mlt4+anbsxQ==",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz",
+      "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==",
       "dev": true,
       "requires": {
         "glob": "^9.2.0"
diff --git a/src/rules/function-no-unknown/index.js b/src/rules/function-no-unknown/index.js
index abbe15f..8167b4a 100644
--- a/src/rules/function-no-unknown/index.js
+++ b/src/rules/function-no-unknown/index.js
@@ -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(
@@ -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),


Test patch:
diff --git a/src/rules/function-no-unknown/__tests__/index.js b/src/rules/function-no-unknown/__tests__/index.js
index c03411e..8afb459 100644
--- a/src/rules/function-no-unknown/__tests__/index.js
+++ b/src/rules/function-no-unknown/__tests__/index.js
@@ -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."
     }
   ],
 
@@ -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"
     }
   ]
 });