File and folder names
Markdown for agentsThis guide checks the names of files and folders, and which files a folder must hold.
Before you start
Section titled “Before you start”- Read Getting started.
The example is a React app with components and features. Some of its names break the team’s conventions:
- archangel.config.ts
Directorysrc/
Directorycomponents/
- Avatar.tsx
- priceTag.tsx
Directoryfeatures/
Directorycart/
- index.ts
Directoryui/
- cart-row.tsx
- cart.container.tsx
- cart.view.tsx
DirectoryorderHistory/
Directoryui/
- orders.view.tsx
Write the rules
Section titled “Write the rules”This config has five rules. The sections below tell you about each one.
import { defineConfig } from '@enhance-eng/archangel';
export default defineConfig({ rules: ({ rule }) => [ rule('folder-names', { folders: 'src/**', mustBeNamed: 'kebab-case', because: 'One style for folders, so an import path is easy to guess.', examples: { rejected: ['src/features/UserProfile/index.ts'] }, }),
rule('component-names', { files: 'src/components/**/*.tsx', mustBeNamed: 'PascalCase', because: 'A component file has the name of the component.', examples: { rejected: ['src/components/user-avatar.tsx'] }, }),
rule('component-exports', { files: 'src/components/**/*.tsx', mustExport: '{FileName}', because: 'Code imports a component by the name of its file.', examples: { rejected: [{ 'src/components/Avatar.tsx': 'export function Picture() {}' }], }, }),
rule('ui-file-names', { files: 'src/features/*/ui/**/*.tsx', mustBeNamed: ['*.view', '*.container'], because: 'A view only shows data. A container gets the data.', examples: { rejected: ['src/features/cart/ui/cart-list.tsx'] }, }),
rule('feature-entry', { folders: 'src/features/*', mustContain: 'index.ts', because: 'Other code imports a feature through its index file.', examples: { rejected: ['src/features/search/ui/search.view.tsx'] }, }), ],});A style for folders
Section titled “A style for folders”folder-names uses folders, not files. The pattern src/** matches each folder inside src.
mustBeNamed: 'kebab-case' gives the style.
The styles are kebab-case, camelCase, PascalCase, snake_case and
SCREAMING_SNAKE_CASE.
A style for files
Section titled “A style for files”component-names gives each component file a name in PascalCase. For a style, archangel reads
the name up to the first dot. So Avatar.tsx has the name Avatar, and Button.test.tsx has the
name Button.
A list of permitted names
Section titled “A list of permitted names”ui-file-names permits two name patterns: *.view and *.container. A name pattern reads the
full name of the file without its last extension, so cart.view.tsx has the full name
cart.view. In a name pattern, * is any text or no text.
*.viewmatchescart.view.tsx.*.viewdoes not matchview.tsx, whose full name isview.*.viewdoes not matchcart.view.extra.tsx, whose full name iscart.view.extra.
One entry of the list must match. A list can mix styles and name patterns. An empty list is a config error.
A file exports the name of its file
Section titled “A file exports the name of its file”component-exports uses an export condition: mustExport: '{FileName}'. {FileName} is the name
of the file in PascalCase. So Avatar.tsx must export Avatar. A re-export and export * count.
The name of the file or its folder can go in a name pattern in each style: {FileName},
{fileName}, {file-name}, {file_name}, {FILE_NAME}, and the same spellings of
{FolderName}.
Each folder has its entry file
Section titled “Each folder has its entry file”feature-entry uses mustContain. Each folder that src/features/* matches must hold
index.ts. To permit one file of a list, write a list:
mustContain: ['index.ts', 'index.tsx'].
Check the names
Section titled “Check the names”-
Check the app:
Terminal $ npx archangel checkerror[must-be-named]: the name of priceTag.tsx is priceTag, which is not PascalCase; in PascalCase the file is PriceTag.tsx--> src/components/priceTag.tsx= help: name it PriceTag.tsx= note: rule: component-names= note: because: A component file has the name of the component.error[must-be-named]: the full name of cart-row.tsx is cart-row, and it must be *.view or *.container--> src/features/cart/ui/cart-row.tsx= help: rename the file so that its name without the extension is *.view or *.container= note: rule: ui-file-names= note: because: A view only shows data. A container gets the data.error[must-contain]: the folder src/features/orderHistory has no file that matches index.ts--> src/features/orderHistory= help: add src/features/orderHistory/index.ts= note: rule: feature-entry= note: because: Other code imports a feature through its index file.error[must-be-named]: the folder src/features/orderHistory is not kebab-case; in kebab-case it is src/features/order-history--> src/features/orderHistory= help: name it src/features/order-history= note: rule: folder-names= note: because: One style for folders, so an import path is easy to guess.checked 8 files and 4 imports: 4 problemsFor what a code means, run `archangel docs must-be-named` or `archangel docs must-contain`.Each error says what is wrong and gives the correct name:
priceTag.tsxis not inPascalCase.cart-row.tsxmatches neither*.viewnor*.container.src/features/orderHistoryhas noindex.ts.src/features/orderHistoryis not inkebab-case.
-
Run the examples:
Terminal $ npx archangel testpass folder-names rejected #1 src/features/UserProfile/index.tspass component-names rejected #1 src/components/user-avatar.tsxpass component-exports rejected #1 src/components/Avatar.tsxpass ui-file-names rejected #1 src/features/cart/ui/cart-list.tsxpass feature-entry rejected #1 src/features/search/ui/search.view.tsx5 examples, none failed; 0 rules without a rejected example
See what the rules cover
Section titled “See what the rules cover”$ npx archangel rulesfolder-names archangel.config.ts:5 because: One style for folders, so an import path is easy to guess. folders in src/** must have names in kebab-case 6 folders · 1 problem
component-names archangel.config.ts:12 because: A component file has the name of the component. files in src/components/**/*.tsx must have names in PascalCase 2 files · 1 problem
component-exports archangel.config.ts:19 because: Code imports a component by the name of its file. files in src/components/**/*.tsx must export a name that matches {FileName} 2 files · 0 problems
ui-file-names archangel.config.ts:28 because: A view only shows data. A container gets the data. files in src/features/*/ui/**/*.tsx must have full names that match *.view or *.container 4 files · 1 problem
feature-entry archangel.config.ts:35 because: Other code imports a feature through its index file. each folder in src/features/* must have a file that matches index.ts 2 folders · 1 problem
Files that no rule judges: 1 src/features/cart/index.tsImports between repository files that no rule judges: 3 src/features/cart/index.ts:1 imports src/features/cart/ui/cart.container.tsx src/features/cart/ui/cart.container.tsx:1 imports src/features/cart/ui/cart.view.tsx src/features/cart/ui/cart.view.tsx:1 imports src/features/cart/ui/cart-row.tsxOutside packages that no rule names: none.The end of the output lists one file and three imports that no rule judges. Name rules judge files, not imports. To check the imports too, add a table.
What archangel does not check
Section titled “What archangel does not check”- Archangel has no rule for the first or the last character of a name, for example a name that
starts with
_. - Archangel does not check the names inside a file, such as names of functions.
mustExportandmayNotExportcheck only exported names.
Next steps
Section titled “Next steps”- Conditions lists each structure and export condition.
- Migrate from eslint-plugin-check-file.