Skip to content

Commit

Permalink
Implement the complete solution for processing the flat configuration…
Browse files Browse the repository at this point in the history
… structure (#95)
  • Loading branch information
daniilsapa authored Oct 10, 2024
1 parent 7057543 commit 3c7a50c
Show file tree
Hide file tree
Showing 70 changed files with 2,056 additions and 740 deletions.
8 changes: 8 additions & 0 deletions .changeset/stale-brooms-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@feature-sliced/steiger-plugin': minor
'@steiger/pretty-reporter': minor
'steiger': minor
'@steiger/types': minor
---

Complete configuration parsing and application logic
6 changes: 3 additions & 3 deletions packages/pretty-reporter/src/format-single-diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import figures from 'figures'
import terminalLink from 'terminal-link'
import chalk from 'chalk'

import type { AugmentedDiagnostic } from './types.js'
import type { Diagnostic } from '@steiger/types'

export function formatSingleDiagnostic(d: AugmentedDiagnostic, cwd: string): string {
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)
Expand All @@ -23,7 +23,7 @@ ${e} ${ruleName}
`.trim()
}

function formatLocation(location: AugmentedDiagnostic['location'], cwd: string) {
function formatLocation(location: Diagnostic['location'], cwd: string) {
let path = relative(cwd, location.path)
if (location.line !== undefined) {
path += `:${location.line}`
Expand Down
8 changes: 4 additions & 4 deletions packages/pretty-reporter/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import chalk from 'chalk'
import figures from 'figures'

import type { AugmentedDiagnostic } from './types.js'
import type { Diagnostic } from '@steiger/types'
import { formatSingleDiagnostic } from './format-single-diagnostic.js'
import { s } from './pluralization.js'

export function formatPretty(diagnostics: Array<AugmentedDiagnostic>, cwd: string) {
export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
if (diagnostics.length === 0) {
return chalk.green(`${figures.tick} No problems found!`)
}
Expand Down Expand Up @@ -43,8 +43,8 @@ export function formatPretty(diagnostics: Array<AugmentedDiagnostic>, cwd: strin
)
}

export function reportPretty(diagnostics: Array<AugmentedDiagnostic>, cwd: string) {
export function reportPretty(diagnostics: Array<Diagnostic>, cwd: string) {
console.error(formatPretty(diagnostics, cwd))
}

export type { AugmentedDiagnostic }
export type { Diagnostic }
7 changes: 0 additions & 7 deletions packages/pretty-reporter/src/types.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/_lib/prepare-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { join, sep } from 'node:path'
import type { readFileSync, existsSync } from 'node:fs'
import type { FsdRoot } from '@feature-sliced/filesystem'
import type { Folder, File, Diagnostic } from '@steiger/types'
import type { Folder, File, PartialDiagnostic } from '@steiger/types'
import { vi } from 'vitest'

/** Parse a multi-line indented string with emojis for files and folders into an FSD root.
Expand Down Expand Up @@ -39,7 +39,7 @@ export function parseIntoFsdRoot(fsMarkup: string, mountTo?: string): FsdRoot {
return parseFolder(lines, mountTo ?? joinFromRoot())
}

export function compareMessages(a: Diagnostic, b: Diagnostic): number {
export function compareMessages(a: PartialDiagnostic, b: PartialDiagnostic): number {
return a.message.localeCompare(b.message) || a.location.path.localeCompare(b.location.path)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { basename, sep } from 'node:path'
import { getAllSlices, getLayers, getSegments, type LayerName } from '@feature-sliced/filesystem'
import type { Diagnostic, Folder, Rule } from '@steiger/types'
import type { PartialDiagnostic, Folder, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

/** Forbid slice names that match some segment’s name in shared (e.g., theme, i18n) */
const ambiguousSliceNames = {
name: `${NAMESPACE}/ambiguous-slice-names`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const layers = getLayers(root)
const sharedLayer = layers.shared
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/excessive-slicing/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { join } from 'node:path'
import { getLayers, getSlices, isSliced } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'

import { groupSlices } from '../_lib/group-slices.js'
import { NAMESPACE } from '../constants.js'
Expand All @@ -16,7 +16,7 @@ const THRESHOLDS = {
const excessiveSlicing = {
name: `${NAMESPACE}/excessive-slicing`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const [layerName, layer] of Object.entries(getLayers(root))) {
if (!isSliced(layer) || !(layerName in THRESHOLDS)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/forbidden-imports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { layerSequence, resolveImport } from '@feature-sliced/filesystem'
import precinct from 'precinct'
const { paperwork } = precinct
import { parse as parseNearestTsConfig } from 'tsconfck'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'

import { indexSourceFiles } from '../_lib/index-source-files.js'
import { NAMESPACE } from '../constants.js'

const forbiddenImports = {
name: `${NAMESPACE}/forbidden-imports`,
async check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []
const { tsconfig } = await parseNearestTsConfig(root.path)
const sourceFileIndex = indexSourceFiles(root)

Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/import-locality/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { resolveImport } from '@feature-sliced/filesystem'
import precinct from 'precinct'
const { paperwork } = precinct
import { parse as parseNearestTsConfig } from 'tsconfck'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'

import { indexSourceFiles } from '../_lib/index-source-files.js'
import { NAMESPACE } from '../constants.js'

const importLocality = {
name: `${NAMESPACE}/import-locality`,
async check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []
const { tsconfig } = await parseNearestTsConfig(root.path)
const sourceFileIndex = indexSourceFiles(root)

Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/inconsistent-naming/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { partition } from 'lodash-es'
import pluralize from 'pluralize'
const { isPlural, plural, singular } = pluralize
import { getLayers, getSlices } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'

import { groupSlices } from '../_lib/group-slices.js'
import { NAMESPACE } from '../constants.js'
Expand All @@ -12,7 +12,7 @@ import { NAMESPACE } from '../constants.js'
const inconsistentNaming = {
name: `${NAMESPACE}/inconsistent-naming`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const { entities } = getLayers(root)
if (entities === undefined) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/insignificant-slice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fs from 'node:fs'
import { sep, join } from 'node:path'
import { parse as parseNearestTsConfig } from 'tsconfck'
import { isSliced, resolveImport, unslicedLayers, type LayerName } from '@feature-sliced/filesystem'
import type { Folder, Diagnostic, Rule } from '@steiger/types'
import type { Folder, PartialDiagnostic, Rule } from '@steiger/types'
import precinct from 'precinct'
const { paperwork } = precinct

Expand All @@ -12,7 +12,7 @@ import { NAMESPACE } from '../constants.js'
const insignificantSlice = {
name: `${NAMESPACE}/insignificant-slice`,
async check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const references = await traceSliceReferences(root)

Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/no-file-segments/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { basename } from 'node:path'
import { getLayers, getSlices, isSliced } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const noFileSegments = {
name: `${NAMESPACE}/no-file-segments`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const layer of Object.values(getLayers(root))) {
if (!isSliced(layer)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/no-layer-public-api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getIndex, getLayers } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

/** Layers that are allowed to have an index file. */
Expand All @@ -9,7 +9,7 @@ const exceptionLayers = ['app']
const noLayerPublicApi = {
name: `${NAMESPACE}/no-layer-public-api`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const [layerName, layer] of Object.entries(getLayers(root))) {
const index = getIndex(layer)
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/no-processes/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { basename } from 'node:path'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const noProcesses = {
name: `${NAMESPACE}/no-processes`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const processesLayer = root.children.find(
(child) => child.type === 'folder' && basename(child.path) === 'processes',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import precinct from 'precinct'
const { paperwork } = precinct
import { parse as parseNearestTsConfig } from 'tsconfck'
import { getIndex, getLayers, getSegments, isSliced, resolveImport } from '@feature-sliced/filesystem'
import type { Folder, File, Diagnostic, Rule } from '@steiger/types'
import type { Folder, File, PartialDiagnostic, Rule } from '@steiger/types'

import { indexSourceFiles } from '../_lib/index-source-files.js'
import { NAMESPACE } from '../constants.js'
Expand All @@ -12,7 +12,7 @@ import { NAMESPACE } from '../constants.js'
const noPublicApiSidestep = {
name: `${NAMESPACE}/no-public-api-sidestep`,
async check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []
const { tsconfig } = await parseNearestTsConfig(root.path)
const sourceFileIndex = indexSourceFiles(root)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { basename } from 'node:path'
import { getAllSegments, conventionalSegmentNames } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'

import { findAllRecursively } from '../_lib/find-all-recursively.js'
import { NAMESPACE } from '../constants.js'
Expand All @@ -9,7 +9,7 @@ import { NAMESPACE } from '../constants.js'
const noReservedFolderNames = {
name: `${NAMESPACE}/no-reserved-folder-names`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const { segment } of getAllSegments(root)) {
if (segment.type === 'file') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { getLayers, isSlice, isSliced } from '@feature-sliced/filesystem'
import type { Folder, Diagnostic, Rule } from '@steiger/types'
import type { Folder, PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const noSegmentlessSlices = {
name: `${NAMESPACE}/no-segmentless-slices`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const layer of Object.values(getLayers(root))) {
if (!isSliced(layer)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { basename } from 'node:path'

import { getLayers, isSliced, conventionalSegmentNames } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const noSegmentsOnSlicedLayers = {
name: `${NAMESPACE}/no-segments-on-sliced-layers`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []
const layers = Object.values(getLayers(root))

for (const layer of layers) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/no-ui-in-app/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'
import { getLayers, getSegments } from '@feature-sliced/filesystem'

const noUiInApp = {
name: `${NAMESPACE}/no-ui-in-app`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const layers = getLayers(root)

Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/public-api/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { join } from 'node:path'
import { getLayers, getSegments, isSliced, getIndex, getSlices } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

/** Require slices (or segments on sliceless layers) to have a public API. */
const publicApi = {
name: `${NAMESPACE}/public-api`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const [layerName, layer] of Object.entries(getLayers(root))) {
if (!isSliced(layer)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/repetitive-naming/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getLayers, getSlices, isSliced } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

/**
Expand All @@ -18,7 +18,7 @@ const wordPattern = /(?:[A-Z]+|[a-z]+)[a-z]*/g
const repetitiveNaming = {
name: `${NAMESPACE}/repetitive-naming`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const layer of Object.values(getLayers(root))) {
if (!isSliced(layer)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/segments-by-purpose/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getLayers, getSegments, getSlices, isSliced } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const BAD_NAMES = ['components', 'hooks', 'helpers', 'utils', 'modals', 'types', 'constants', 'consts', 'const']
Expand All @@ -8,7 +8,7 @@ const BAD_NAMES = ['components', 'hooks', 'helpers', 'utils', 'modals', 'types',
const segmentsByPurpose = {
name: `${NAMESPACE}/segments-by-purpose`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

for (const layer of Object.values(getLayers(root))) {
if (layer === null) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/shared-lib-grouping/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getLayers, getSegments } from '@feature-sliced/filesystem'
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'

const THRESHOLD = 15
Expand All @@ -8,7 +8,7 @@ const THRESHOLD = 15
const sharedLibGrouping = {
name: `${NAMESPACE}/shared-lib-grouping`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

const { shared } = getLayers(root)
if (!shared) {
Expand Down
4 changes: 2 additions & 2 deletions packages/steiger-plugin-fsd/src/typo-in-layer-name/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Diagnostic, Rule } from '@steiger/types'
import type { PartialDiagnostic, Rule } from '@steiger/types'
import { NAMESPACE } from '../constants.js'
import { LayerName, layerSequence } from '@feature-sliced/filesystem'
import { distance } from 'fastest-levenshtein'
Expand All @@ -10,7 +10,7 @@ const LEVENSHTEIN_DISTANCE_UPPER_BOUND = 3
const typoInLayerName = {
name: `${NAMESPACE}/typo-in-layer-name`,
check(root) {
const diagnostics: Array<Diagnostic> = []
const diagnostics: Array<PartialDiagnostic> = []

// construct list of suggestions, like [{ input: 'shraed', suggestion: 'shared', distance: 2 }, ...],
// limit Levenshtein distance upper bound to 3,
Expand Down
Loading

0 comments on commit 3c7a50c

Please sign in to comment.