Skip to content

Commit 82bca31

Browse files
committed
Add new linting rule and fix documentation being broken
1 parent 62b911f commit 82bca31

File tree

20 files changed

+564
-52
lines changed

20 files changed

+564
-52
lines changed

.github/workflows/pull-request.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ jobs:
3939
id: info
4040
uses: ./.github/actions/src/info
4141

42+
- name: Echo Information about docserver
43+
run: echo ${{ steps.info.outputs.docserver }}
44+
45+
- name: Echo Information about devserver
46+
run: echo ${{ steps.info.outputs.devserver }}
47+
4248
outputs:
4349
bundles: ${{ steps.info.outputs.bundles }}
4450
libs: ${{ steps.info.outputs.libs }}
@@ -221,7 +227,7 @@ jobs:
221227
needs:
222228
- libraries
223229
- find-packages
224-
if: ${{ needs.find-packages.outputs.docserver.changes == 'true' }}
230+
if: ${{ needs.find-packages.outputs.docserver.changes }}
225231

226232
steps:
227233
- name: Check out source code
@@ -255,3 +261,12 @@ jobs:
255261

256262
- name: Lint Everything
257263
run: yarn lint:all
264+
265+
- name: Build Manifest
266+
run: yarn buildtools manifest
267+
268+
- name: Upload Manifest
269+
uses: actions/upload-artifact@v4
270+
with:
271+
name: manifest
272+
path: ./build/modules.json

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
}
1919
],
2020
"eslint.validate": [
21+
"github-actions-workflow",
2122
"javascript",
2223
"javascriptreact",
2324
"json",
24-
"mdx",
25+
"markdown",
2526
"typescript",
2627
"typescriptreact",
2728
"yml",

docs/src/lib/dev/curve.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: curve
2+
title: Curve Bundle
33
---
44

55
# Introduction

docs/src/lib/dev/devdocs.data.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@ import { createContentLoader } from 'vitepress';
66

77
const files = await fs.readdir(import.meta.dirname, { withFileTypes: true });
88

9+
// Any markdown files within the lib/dev directory will be considered
10+
// except for the index.md file
911
const filesToInclude = files.filter(each => {
1012
if (!each.isFile()) return false;
1113
if (pathlib.extname(each.name) !== '.md') return false;
1214
return each.name !== 'index.md';
1315
}).map(each => {
16+
// Paths are resolved relative to the src directory
1417
return pathlib.join('/lib/dev', each.name);
1518
});
1619

17-
export default createContentLoader(filesToInclude);
20+
export default createContentLoader(filesToInclude, {
21+
transform(data) {
22+
// Append the base path
23+
data.forEach(each => {
24+
each.url = `/devdocs${each.url}`;
25+
});
26+
return data;
27+
}
28+
});

docs/src/lib/dev/game.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: game
2+
title: Game Bundle
33
---
44

55
# Introduction

docs/src/lib/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
## Modules Developer Documentation
1+
# Modules Developer Documentation
22
If you're developing for a specific module, its developer documentation can be found under [this](./dev/) section.
33

4-
## Common Modules Libraries
4+
# Common Libraries
55

66
- [Lint Plugin](./lintplugin/)
77
- [Modules Lib](./modules-lib/)

docs/src/lib/lintplugin/2-rules.md

Lines changed: 132 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,138 @@ import path from 'pathlib'
5151
// both import statements will be validated!
5252
```
5353

54+
## `no-barrel-imports`
55+
Enforces that imports from a certain source uses individual imports intead of the main barrel import.
56+
57+
This rule was primarily motivated by packages like `lodash` and `@mui`, which re-export all their functionalities
58+
through the main export, but also make each function available in a separate package:
59+
```ts
60+
// Imports from the root package
61+
import _ from 'lodash'
62+
_.memoize(func)
63+
64+
import { memoize } from 'lodash'
65+
memoize(func)
66+
// vs importing from a "sub-package"
67+
import memoize 'lodash/memoize'
68+
memoize(func)
69+
```
70+
71+
The reason for these "per method imports" is to help bundlers more effectively tree-shake and thus more effectively reduce final bundle size.
72+
73+
> [!INFO] Why not directly use "per method packages"?
74+
> In theory, `lodash` provides its sub-packages as actual packages you can install separately without having to install the entire `lodash` bundle.
75+
> However, the `lodash` [documentation](https://lodash.com/per-method-packages) recommends against this practice for reasons mentioned there.
76+
77+
The exception to this is Typescript "type-only" imports, since those automatically get removed from the output source code:
78+
```ts
79+
// Are perfectly ok
80+
import type _ from 'lodash'
81+
import type { memoize } from 'lodash'
82+
```
83+
84+
### Fixes
85+
The rule replaces the original import with different import statements from each of the subpackages:
86+
```ts
87+
import { memoize } from 'lodash'
88+
// gets autofixed to
89+
import memoize from 'lodash/memoize'
90+
```
91+
92+
If you aliased the import, the appropriate alias name will be used:
93+
```ts
94+
import { memoize as func } from 'lodash'
95+
// gets autofixed to
96+
import func from 'lodash/memoize'
97+
```
98+
99+
Multiple imports from the root package get transformed like this:
100+
```ts
101+
import { memoize as func, cloneDeep } from 'lodash'
102+
// gets autofixed to
103+
import func from 'lodash/memoize'
104+
import cloneDeep from 'lodash/cloneDeep'
105+
import cloneDeep from 'lodash/cloneDeep'
106+
```
107+
108+
Type-only imports, when mixed with default imports, also get autofixed:
109+
```ts
110+
import { type memoize as func, cloneDeep } from 'lodash'
111+
// gets autofixed to
112+
import type func from 'lodash/memoize'
113+
import cloneDeep from 'lodash/cloneDeep'
114+
```
115+
116+
> [!WARNING]
117+
> This only tells the rule what import sources to check for. It doesn't perform any kind of verification that the sub-package export paths
118+
> are actually available. For example, the rule will not actually verify that `lodash/memoize` is a valid import path and that it does have a default export
119+
120+
### Options
121+
The rule should be configured with an array of package names to check:
122+
```ts
123+
rules: {
124+
'@sourceacademy/no-barrel-imports': ['error', ['lodash']]
125+
}
126+
```
127+
128+
129+
### ✅ Examples of **correct** code for this rule:
130+
131+
```ts
132+
// with @sourceacademy/no-barrel-imports: ['error', ['lodash']]
133+
134+
// Lone default or namespace imports are ok
135+
import _ from 'lodash'
136+
import * as _ from 'lodash'
137+
138+
// Type-only imports are okay
139+
import type _ from 'lodash';
140+
import type { memoize } from 'lodash';
141+
```
142+
143+
### ❌ Examples of **incorrect** code for this rule:
144+
```ts
145+
// with @sourceacademy/no-barrel-imports: ['error', ['lodash']]
146+
147+
// Regular Import
148+
import { memoize } from 'lodash'
149+
150+
// Default import mixed with type imports
151+
import _, { type memoize } from 'lodash';
152+
```
153+
154+
## `region-comment`
155+
This rule enforces that each `// #region` comment is named and paired with a corresponding `// #endregion` comment.
156+
157+
### ✅ Examples of **correct** code for this rule:
158+
```ts
159+
// #region Region1
160+
export function foo() {}
161+
// #endregion Region1
162+
```
163+
164+
Regions can overlap:
165+
```ts
166+
// #region Region1
167+
// #region Region2
168+
export function foo() {}
169+
// #endregion Region2
170+
// #endregion Region1
171+
```
172+
173+
### ❌ Examples of **incorrect** code for this rule:
174+
175+
```ts
176+
// Missing name for region
177+
// #region
178+
export function foo() {}
179+
// #endregion
180+
181+
// Missing #region tag
182+
export function bar() {}
183+
// #endregion 1
184+
```
185+
54186
## `tab-type`
55187

56188
Enforces that tabs have a default export using the `defineTab` helper.
@@ -108,34 +240,3 @@ export default tabHelper({
108240
});
109241
```
110242

111-
## `region-comment`
112-
This rule enforces that each `// #region` comment is named and paired with a corresponding `// #endregion` comment.
113-
114-
### ✅ Examples of **correct** code for this rule:
115-
```ts
116-
// #region Region1
117-
export function foo() {}
118-
// #endregion Region1
119-
```
120-
121-
Regions can overlap:
122-
```ts
123-
// #region Region1
124-
// #region Region2
125-
export function foo() {}
126-
// #endregion Region2
127-
// #endregion Region1
128-
```
129-
130-
### ❌ Examples of **incorrect** code for this rule:
131-
132-
```ts
133-
// Missing name for region
134-
// #region
135-
export function foo() {}
136-
// #endregion
137-
138-
// Missing #region tag
139-
export function bar() {}
140-
// #endregion 1
141-
```

docs/src/lib/lintplugin/3-config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Configurations
2+
title: Config Reference
33
---
44
<script setup>
55
import { data } from './configs.data.ts';

docs/src/repotools/docserver/1-overview.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ documentation in those pages or create rewrites so that users are automatically
5656

5757
Instead, the links in the sidebar link to the page (if it is a markdown file), or to a child within the folder that has the same name as that folder.
5858

59-
The specific configuration for this behaviour can be found in the Vitepress config file, and the documentation for those options can be found on the Vitepress website:
60-
61-
<<< ../../../.vitepress/config.ts {65-75 ts:line-numbers}
62-
6359
## Documentation for `modules-lib`
6460
The documentation for `@sourceacademy/modules-lib` is automatically generated by Typedoc. The configuration options for this generation are found in that folder. The documentation for `@sourceacademy/modules-lib` should be built before this server is built.
6561

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export default tseslint.config(
160160
'no-empty': ['error', { allowEmptyCatch: true }],
161161

162162
'@sourceacademy/default-import-name': ['warn', { path: 'pathlib' }],
163+
'@sourceacademy/no-barrel-imports': ['error', ['lodash']],
163164
'@sourceacademy/region-comment': 'error',
164165

165166
'@stylistic/brace-style': ['warn', '1tbs', { allowSingleLine: true }],

0 commit comments

Comments
 (0)