Skip to content

Commit

Permalink
Merge branch 'master' into e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
illright committed Dec 26, 2024
2 parents 0a7f7a4 + caa9ede commit c2baf79
Show file tree
Hide file tree
Showing 37 changed files with 1,896 additions and 1,434 deletions.
5 changes: 5 additions & 0 deletions .changeset/curvy-guests-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@feature-sliced/steiger-plugin': patch
---

Change the plugin name string to match the npm package name
5 changes: 5 additions & 0 deletions .changeset/early-knives-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@steiger/pretty-reporter': minor
---

Make printed diagnostic location more readable
5 changes: 5 additions & 0 deletions .changeset/eleven-numbers-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'steiger': patch
---

Handle an edge case with well-known ignores (like .DS_Store on macOS) when applying glob exclusions
5 changes: 0 additions & 5 deletions .changeset/little-zebras-pay.md

This file was deleted.

5 changes: 5 additions & 0 deletions .changeset/ten-weeks-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@feature-sliced/steiger-plugin': patch
---

Add an exception to the `insignificant-slice` rule when the only usage site is the App layer
5 changes: 5 additions & 0 deletions .changeset/twelve-snakes-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'steiger': patch
---

Fix the "--version" command outputting "unknown"
70 changes: 70 additions & 0 deletions .github/workflows/bundle-size-trusted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This is the trusted counterpart of the Bundle size workflow.
# It generates a report and posts a comment on the PR.

name: Bundle size (trusted)

on:
workflow_run:
workflows: [Bundle size]
types:
- completed

permissions:
pull-requests: write

jobs:
print:
name: Print the sizes
runs-on: ubuntu-latest
steps:
- name: Download the sizes
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: '.'
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}

- name: Create the report
id: create-report
uses: actions/github-script@v7
with:
result-encoding: string
script: |
function parseDuOutput(output) {
return Object.fromEntries(output.trim().split('\n').map(line => {
const [size, folderName] = line.split(/\s+/);
const [_packages, packageName, _dist] = folderName.split('/');
return [packageName, parseInt(size, 10)];
}));
}
function formatSize(sizeInBytes) {
if (sizeInBytes < 1000) {
return `${sizeInBytes} B`;
} else {
const sizeInKb = sizeInBytes / 1000;
return `${sizeInKb.toFixed(2)} KB`;
}
}
const fs = require('fs');
const sizes = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.base_ref) }}}.txt`, 'utf8'));
const sizesPR = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.head_ref) }}}.txt`, 'utf8'));
core.summary.addHeading('📊 Package size report', '3');
core.summary.addTable([
['Package', 'Before', 'After'].map((data) => ({ data, header: true })),
...Object.keys(sizes).map((packageName) => {
const size = sizes[packageName];
const sizePR = sizesPR[packageName];
return [packageName, formatSize(size), sizePR === size ? 'No change' : formatSize(sizePR)];
}),
]);
const report = core.summary.stringify();
core.summary.write();
return report;
- name: Post the report to the PR
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
with:
message: ${{ steps.create-report.outputs.result }}
pr-number: ${{ github.event.workflow_run.pull_requests.number }}
comment-tag: bundle-size
44 changes: 44 additions & 0 deletions .github/workflows/bundle-size-untrusted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This workflow builds the packages on the base branch and the PR branch, and then records the sizes of the built packages.
# The size comparison is done in a separate workflow because this one can't leave PR comments.

name: Bundle size

on:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build:
name: Build on the base branch and the PR branch
strategy:
matrix:
branch:
- ${{ github.base_ref }}
- ${{ github.head_ref }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ matrix.branch }}

- name: Setup
uses: ./.github/actions/setup

- name: Build the packages
run: turbo run build

- name: Collect sizes in bytes
id: sizes
run: du -sb packages/*/dist > sizes-${{ matrix.branch }}.txt

- name: Upload the sizes
uses: actions/upload-artifact@v4
with:
name: sizes-${{ matrix.branch }}
path: sizes-${{ matrix.branch }}.txt
53 changes: 53 additions & 0 deletions .github/workflows/pkg-pr-new.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish Approved Pull Requests to pkg.pr.new
on:
pull_request_review:
types: [submitted]

permissions:
contents: read
pull-requests: read

jobs:
check:
# First, trigger a permissions check on the user approving the pull request.
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
outputs:
has-permissions: ${{ steps.checkPermissions.outputs.result }}
steps:
- name: Check permissions
id: checkPermissions
uses: actions/github-script@v7
with:
result-encoding: string
# The approver must have write access to the repository to trigger the package preview.
script: |
const { data: { permission } } =
await github.rest.repos.getCollaboratorPermissionLevel({
...context.repo,
username: context.actor,
});
return permission === 'write' || permission === 'admin';
publish:
needs: check
# Publish the preview package only if the permissions check passed.
if: needs.check.outputs.has-permissions == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm exec turbo build

- run: pnpm dlx pkg-pr-new publish './packages/*'
35 changes: 17 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,23 @@ Currently, Steiger is not extendable with more rules, though that will change in
</tr>
</thead>
<tbody>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/ambiguous-slice-names/README.md"><code>ambiguous-slice-names</code></a></td> <td>Forbid slice names that that match some segment’s name in the Shared layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/excessive-slicing/README.md"><code>excessive-slicing</code></a></td> <td>Forbid having too many ungrouped slices or too many slices in a group.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/forbidden-imports/README.md"><code>forbidden-imports</code></a></td> <td>Forbid imports from higher layers and cross-imports between slices on the same layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/inconsistent-naming/README.md"><code>inconsistent-naming</code></a></td> <td>Ensure that all entities are named consistently in terms of pluralization.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/insignificant-slice/README.md"><code>insignificant-slice</code></a></td> <td>Detect slices that have just one reference or no references to them at all.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-layer-public-api/README.md"><code>no-layer-public-api</code></a></td> <td>Forbid index files on the layer level.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-public-api-sidestep/README.md"><code>no-public-api-sidestep</code></a></td> <td>Forbid going around the public API of a slice to import directly from an internal module in a slice.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-reserved-folder-names/README.md"><code>no-reserved-folder-names</code></a></td> <td>Forbid subfolders in segments that have the same name as other conventional segments.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-segmentless-slices/README.md"><code>no-segmentless-slices</code></a></td> <td>Forbid slices that don't have any segments.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/README.md"><code>no-segments-on-sliced-layers</code></a></td> <td>Forbid segments (like ui, lib, api ...) that appear directly in sliced layer folders (entities, features, ...)</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-ui-in-app/README.md"><code>no-ui-in-app</code></a></td> <td>Forbid having the <code>ui</code> segment on the App layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/public-api/README.md"><code>public-api</code></a></td> <td>Require slices (and segments on sliceless layers like Shared) to have a public API definition.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/repetitive-naming/README.md"><code>repetitive-naming</code></a></td> <td>Ensure that all entities are named consistently in terms of pluralization.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/segments-by-purpose/README.md"><code>segments-by-purpose</code></a></td> <td>Discourage the use of segment names that group code by its essence, and instead encourage grouping by purpose</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/shared-lib-grouping/README.md"><code>shared-lib-grouping</code></a></td> <td>Forbid having too many ungrouped modules in <code>shared/lib</code>.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/typo-in-layer-name/README.md"><code>typo-in-layer-name</code></a></td> <td>Ensure that all layers are named without any typos.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-processes/README.md"><code>no-processes</code></a></td> <td>Discourage the use of the deprecated Processes layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/import-locality/README.md"><code>import-locality</code></a></td> <td>Require that imports from the same slice be relative and imports from one slice to another be absolute.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/ambiguous-slice-names/README.md"><code>fsd/ambiguous-slice-names</code></a></td> <td>Forbid slice names that that match some segment’s name in the Shared layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/excessive-slicing/README.md"><code>fsd/excessive-slicing</code></a></td> <td>Forbid having too many ungrouped slices or too many slices in a group.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/forbidden-imports/README.md"><code>fsd/forbidden-imports</code></a></td> <td>Forbid imports from higher layers and cross-imports between slices on the same layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/inconsistent-naming/README.md"><code>fsd/inconsistent-naming</code></a></td> <td>Ensure that all entities are named consistently in terms of pluralization.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/insignificant-slice/README.md"><code>fsd/insignificant-slice</code></a></td> <td>Detect slices that have just one reference or no references to them at all.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-layer-public-api/README.md"><code>fsd/no-layer-public-api</code></a></td> <td>Forbid index files on the layer level.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-public-api-sidestep/README.md"><code>fsd/no-public-api-sidestep</code></a></td> <td>Forbid going around the public API of a slice to import directly from an internal module in a slice.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-reserved-folder-names/README.md"><code>fsd/no-reserved-folder-names</code></a></td> <td>Forbid subfolders in segments that have the same name as other conventional segments.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-segmentless-slices/README.md"><code>fsd/no-segmentless-slices</code></a></td> <td>Forbid slices that don't have any segments.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/README.md"><code>fsd/no-segments-on-sliced-layers</code></a></td> <td>Forbid segments (like ui, lib, api ...) that appear directly in sliced layer folders (entities, features, ...)</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-ui-in-app/README.md"><code>fsd/no-ui-in-app</code></a></td> <td>Forbid having the <code>ui</code> segment on the App layer.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/public-api/README.md"><code>fsd/public-api</code></a></td> <td>Require slices (and segments on sliceless layers like Shared) to have a public API definition.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/repetitive-naming/README.md"><code>fsd/repetitive-naming</code></a></td> <td>Ensure that all entities are named consistently in terms of pluralization.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/segments-by-purpose/README.md"><code>fsd/segments-by-purpose</code></a></td> <td>Discourage the use of segment names that group code by its essence, and instead encourage grouping by purpose</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/shared-lib-grouping/README.md"><code>fsd/shared-lib-grouping</code></a></td> <td>Forbid having too many ungrouped modules in <code>shared/lib</code>.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/typo-in-layer-name/README.md"><code>fsd/typo-in-layer-name</code></a></td> <td>Ensure that all layers are named without any typos.</td> </tr>
<tr> <td><a href="./packages/steiger-plugin-fsd/src/no-processes/README.md"><code>fsd/no-processes</code></a></td> <td>Discourage the use of the deprecated Processes layer.</td> </tr>
</tbody>
</table>

Expand Down
21 changes: 10 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
"name": "@steiger/root",
"private": true,
"scripts": {
"format": "prettier --write . \"!packages/** !tooling/**\" --cache",
"check-formatting": "prettier --check . \"!packages/** !tooling/**\" --cache",
"format": "prettier --cache --write . \"!packages/**\" \"!tooling/**\"",
"check-formatting": "prettier --cache --check . \"!packages/**\" \"!tooling/**\"",
"check-monorepo": "manypkg check",
"prepare": "husky"
},
"engines": {
"node": ">= 20"
"node": ">= 18"
},
"packageManager": "[email protected]",
"dependencies": {
"@changesets/cli": "^2.27.9",
"@manypkg/cli": "^0.21.4",
"devDependencies": {
"@changesets/cli": "^2.27.10",
"@manypkg/cli": "^0.23.0",
"@steiger/eslint-config": "workspace:*",
"@tsconfig/node-lts": "^20.1.3",
"eslint": "^9.12.0",
"husky": "^9.1.6",
"eslint": "^9.16.0",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"turbo": "^2.1.3"
"prettier": "^3.4.2",
"turbo": "^2.3.3"
},
"lint-staged": {
"*": "prettier --write --ignore-unknown",
Expand Down
13 changes: 7 additions & 6 deletions packages/pretty-reporter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@
"@steiger/eslint-config": "workspace:*",
"@steiger/tsconfig": "workspace:*",
"@steiger/types": "workspace:*",
"@total-typescript/ts-reset": "^0.5.1",
"@types/node": "^20.16.11",
"eslint": "^9.12.0",
"prettier": "^3.3.3",
"tsx": "^4.19.1",
"typescript": "^5.6.3"
"@total-typescript/ts-reset": "^0.6.1",
"@types/node": "^18.11.9",
"eslint": "^9.16.0",
"prettier": "^3.4.2",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
},
"dependencies": {
"chalk": "^5.3.0",
"figures": "^6.1.0",
"picocolors": "^1.1.1",
"terminal-link": "^3.0.0"
}
}
18 changes: 9 additions & 9 deletions packages/pretty-reporter/src/format-single-diagnostic.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { relative } from 'node:path'
import figures from 'figures'
import terminalLink from 'terminal-link'
import chalk from 'chalk'
import pc from 'picocolors'
import type { Diagnostic } from '@steiger/types'

export function formatSingleDiagnostic(d: Diagnostic, cwd: string): string {
const x = d.severity === 'error' ? chalk.red(figures.cross) : chalk.yellow(figures.warning)
const s = chalk.reset(figures.lineDownRight)
const bar = chalk.reset(figures.lineVertical)
const e = chalk.reset(figures.lineUpRight)
const message = chalk.reset(d.message)
const autofixable = d.fixes !== undefined && d.fixes.length > 0 ? chalk.green(`${figures.tick} Auto-fixable`) : null
const location = chalk.gray(formatLocation(d.location, cwd))
const ruleName = chalk.blue(terminalLink(d.ruleName, d.getRuleDescriptionUrl(d.ruleName).toString()))
const x = d.severity === 'error' ? pc.red(figures.cross) : pc.yellow(figures.warning)
const s = pc.reset(figures.lineDownRight)
const bar = pc.reset(figures.lineVertical)
const e = pc.reset(figures.lineUpRight)
const message = pc.reset(d.message)
const autofixable = d.fixes !== undefined && d.fixes.length > 0 ? pc.green(`${figures.tick} Auto-fixable`) : null
const location = pc.underline(formatLocation(d.location, cwd))
const ruleName = pc.blue(terminalLink(d.ruleName, d.getRuleDescriptionUrl(d.ruleName).toString()))

return `
${s} ${location}
Expand Down
14 changes: 7 additions & 7 deletions packages/pretty-reporter/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import chalk from 'chalk'
import pc from 'picocolors'
import figures from 'figures'
import type { Diagnostic } from '@steiger/types'

Expand All @@ -7,7 +7,7 @@ import { s } from './pluralization.js'

export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
if (diagnostics.length === 0) {
return chalk.green(`${figures.tick} No problems found!`)
return pc.green(`${figures.tick} No problems found!`)
}

const errors = diagnostics.filter((d) => d.severity === 'error')
Expand All @@ -16,17 +16,17 @@ export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
let footer =
'Found ' +
[
errors.length > 0 && chalk.red.bold(`${errors.length} error${s(errors.length)}`),
warnings.length > 0 && chalk.yellow.bold(`${warnings.length} warning${s(warnings.length)}`),
errors.length > 0 && pc.bold(pc.red(`${errors.length} error${s(errors.length)}`)),
warnings.length > 0 && pc.bold(pc.yellow(`${warnings.length} warning${s(warnings.length)}`)),
]
.filter(Boolean)
.join(' and ')

const autofixable = diagnostics.filter((d) => (d.fixes?.length ?? 0) > 0)
if (autofixable.length === diagnostics.length) {
footer += ` (all can be fixed automatically with ${chalk.green.bold('--fix')})`
footer += ` (all can be fixed automatically with ${pc.bold(pc.green('--fix'))})`
} else if (autofixable.length > 0) {
footer += ` (${autofixable.length} can be fixed automatically with ${chalk.green.bold('--fix')})`
footer += ` (${autofixable.length} can be fixed automatically with ${pc.bold(pc.green('--fix'))})`
} else {
footer += ' (none can be fixed automatically)'
}
Expand All @@ -36,7 +36,7 @@ export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
diagnostics.map((d) => formatSingleDiagnostic(d, cwd)).join('\n\n') +
'\n\n' +
// Due to formatting characters, it won't be exactly the size of the footer, that is okay
chalk.gray(figures.line.repeat(footer.length)) +
pc.gray(figures.line.repeat(footer.length)) +
'\n ' +
footer +
'\n'
Expand Down
Loading

0 comments on commit c2baf79

Please sign in to comment.