diff --git a/packages/rstack/THIRD_PARTY_NOTICES.md b/packages/rstack/THIRD_PARTY_NOTICES.md index ecbbcb9..e083d50 100644 --- a/packages/rstack/THIRD_PARTY_NOTICES.md +++ b/packages/rstack/THIRD_PARTY_NOTICES.md @@ -30,6 +30,34 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +## micromatch + +This package includes bundled code from [micromatch](https://github.com/micromatch/micromatch). + +License: MIT + +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + ## Husky Portions of the Git hook installer and runtime are derived from [Husky](https://github.com/typicode/husky). diff --git a/packages/rstack/package.json b/packages/rstack/package.json index fe34902..6ff9ace 100644 --- a/packages/rstack/package.json +++ b/packages/rstack/package.json @@ -65,8 +65,10 @@ "@rstackjs/test-utils": "catalog:", "@rstest/adapter-rsbuild": "catalog:", "@rstest/adapter-rslib": "catalog:", + "@types/micromatch": "catalog:", "@types/node": "catalog:", "lint-staged": "catalog:", + "micromatch": "catalog:", "rslog": "catalog:", "typescript": "catalog:" }, diff --git a/packages/rstack/src/fmt/config.ts b/packages/rstack/src/fmt/config.ts index 93a2ca3..d27ea93 100644 --- a/packages/rstack/src/fmt/config.ts +++ b/packages/rstack/src/fmt/config.ts @@ -1,4 +1,6 @@ -import { dirname } from 'node:path'; +import { dirname, relative } from 'node:path'; +import micromatch from 'micromatch'; +import type { Options as PrettierOptions } from 'prettier'; import type { FmtConfig, FmtConfigDefinition, ResolvedFmtConfig } from './types.ts'; type ResolveFmtConfigOptions = { @@ -19,6 +21,47 @@ const normalizeFmtConfig = (config: FmtConfig | undefined, rootPath: string): Re }; }; +const pathMatchesGlobs = ( + filePath: string, + patterns: string | string[], + excludedPatterns?: string | string[], +): boolean => { + const patternList = Array.isArray(patterns) ? patterns : [patterns]; + const withSlashes = patternList.filter((pattern) => pattern.includes('/')); + const withoutSlashes = patternList.filter((pattern) => !pattern.includes('/')); + + return ( + micromatch.isMatch(filePath, withoutSlashes, { + ignore: excludedPatterns, + basename: true, + dot: true, + }) || + micromatch.isMatch(filePath, withSlashes, { + ignore: excludedPatterns, + basename: false, + dot: true, + }) + ); +}; + +/** Applies matching overrides to the shared formatter options. */ +const resolveFmtOptions = (filePath: string, config: ResolvedFmtConfig): PrettierOptions => { + if (config.overrides.length === 0) { + return config.baseOptions; + } + + const options = { ...config.baseOptions }; + const relativeFilePath = relative(config.rootPath, filePath); + + for (const override of config.overrides) { + if (pathMatchesGlobs(relativeFilePath, override.files, override.excludeFiles)) { + Object.assign(options, override.options); + } + } + + return options; +}; + /** Resolves a formatter config definition and its project root. */ const resolveFmtConfig = async ({ definition, @@ -31,4 +74,4 @@ const resolveFmtConfig = async ({ return normalizeFmtConfig(config, rootPath); }; -export { normalizeFmtConfig, resolveFmtConfig }; +export { normalizeFmtConfig, resolveFmtConfig, resolveFmtOptions }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 270eae0..14048bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,6 +58,9 @@ catalogs: '@testing-library/react': specifier: ^16.3.2 version: 16.3.2 + '@types/micromatch': + specifier: ^4.0.10 + version: 4.0.10 '@types/node': specifier: ^24.13.3 version: 24.13.3 @@ -79,6 +82,9 @@ catalogs: lint-staged: specifier: ^17.2.0 version: 17.2.0 + micromatch: + specifier: 4.0.8 + version: 4.0.8 prettier: specifier: 3.9.6 version: 3.9.6 @@ -331,12 +337,18 @@ importers: '@rstest/adapter-rslib': specifier: 'catalog:' version: 0.11.4(@rslib/core@1.0.0-beta.1)(@rstest/core@0.11.4)(typescript@7.0.2) + '@types/micromatch': + specifier: 'catalog:' + version: 4.0.10 '@types/node': specifier: 'catalog:' version: 24.13.3 lint-staged: specifier: 'catalog:' version: 17.2.0 + micromatch: + specifier: 'catalog:' + version: 4.0.8 rslog: specifier: 'catalog:' version: 2.3.0 @@ -919,6 +931,9 @@ packages: '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/braces@3.0.5': + resolution: {integrity: sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -943,6 +958,9 @@ packages: '@types/mdx@2.0.14': resolution: {integrity: sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==} + '@types/micromatch@4.0.10': + resolution: {integrity: sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1139,6 +1157,10 @@ packages: body-scroll-lock@4.0.0-beta.0: resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + buffer-image-size@0.6.4: resolution: {integrity: sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==} engines: {node: '>=4.0'} @@ -1290,6 +1312,10 @@ packages: picomatch: optional: true + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + flexsearch@0.8.212: resolution: {integrity: sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==} @@ -1388,6 +1414,10 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -1626,6 +1656,10 @@ packages: micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -1659,6 +1693,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} @@ -2045,6 +2083,10 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} @@ -2661,6 +2703,8 @@ snapshots: '@types/aria-query@5.0.4': {} + '@types/braces@3.0.5': {} + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -2688,6 +2732,10 @@ snapshots: '@types/mdx@2.0.14': {} + '@types/micromatch@4.0.10': + dependencies: + '@types/braces': 3.0.5 + '@types/ms@2.1.0': {} '@types/node@24.13.3': @@ -2805,6 +2853,10 @@ snapshots: body-scroll-lock@4.0.0-beta.0: {} + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + buffer-image-size@0.6.4: dependencies: '@types/node': 24.13.3 @@ -2936,6 +2988,10 @@ snapshots: optionalDependencies: picomatch: 4.0.5 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + flexsearch@0.8.212: {} get-east-asian-width@1.6.0: {} @@ -3110,6 +3166,8 @@ snapshots: is-hexadecimal@2.0.1: {} + is-number@7.0.0: {} + is-plain-obj@4.1.0: {} js-tokens@4.0.0: {} @@ -3621,6 +3679,11 @@ snapshots: transitivePeerDependencies: - supports-color + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + min-indent@1.0.1: {} ms@2.1.3: {} @@ -3656,6 +3719,8 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.2: {} + picomatch@4.0.4: {} picomatch@4.0.5: {} @@ -4047,6 +4112,10 @@ snapshots: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + toggle-selection@1.0.6: {} trim-lines@3.0.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3f69109..1421ae9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -28,6 +28,7 @@ catalog: '@testing-library/dom': '^10.4.1' '@testing-library/jest-dom': '^7.0.0' '@testing-library/react': '^16.3.2' + '@types/micromatch': '^4.0.10' '@types/node': '^24.13.3' '@types/react': '^19.2.17' '@types/react-dom': '^19.2.3' @@ -36,6 +37,7 @@ catalog: 'happy-dom': '^20.11.1' 'heading-case': '^1.1.4' 'lint-staged': '^17.2.0' + 'micromatch': '4.0.8' prettier: '3.9.6' 'prettier-plugin-packagejson': '^3.0.2' 'react': '^19.2.8'