@rushstack/eslint-plugin-packlets 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,201 +1,201 @@
1
- # @rushstack/eslint-plugin-packlets
2
-
3
- Packlets provide a lightweight alternative to NPM packages for organizing source files within a single project. The formalism is validated using ESLint rules.
4
-
5
- ## Motivation
6
-
7
- When building a large application, it's a good idea to organize source files into modules, so that their dependencies can be managed. For example, suppose an application's source files can be grouped as follows:
8
-
9
- - `src/logging/*.ts` - the logging system
10
- - `src/data-model/*.ts` - the data model
11
- - `src/reports/*.ts` - the report engine
12
- - `src/*.ts` - other arbitrary files such as startup code and the main application
13
-
14
- Using file folders is helpful, but it's not very strict. Files under `src/logging` can easily import files from `/src/reports`, creating a confusing circular import. They can also import arbitrary application files. Also, there is no clear distinction between which files are the "public API" for `src/logging` versus its private implementation details.
15
-
16
- All these problems can be solved by reorganizing the project into NPM packages (or [Rush projects](https://rushjs.io/)). Something like this:
17
-
18
- - `@my-app/logging` - the logging system
19
- - `@my-app/data-model` - the data model
20
- - `@my-app/reports` - the report engine
21
- - `@my-app/application` - other arbitrary files such as startup code and the main application
22
-
23
- However, separating code in this way has some downsides. The projects need to build separately, which has some tooling costs (for example, "watch mode" now needs to consider multiple projects). In a large monorepo, the library may attract other consumers, before the API has been fully worked out.
24
-
25
- Packlets provide a lightweight alternative that offers many of the same benefits of packages, but without the `package.json` file. It's a great way to prototype your project organization before later graduating your packlets into proper NPM packages.
26
-
27
- ## 5 rules for packlets
28
-
29
- With packlets, our folders would be reorganized as follows:
30
-
31
- - `src/packlets/logging/*.ts` - the logging system
32
- - `src/packlets/data-model/*.ts` - the data model
33
- - `src/packlets/reports/*.ts` - the report engine
34
- - `src/*.ts` - other arbitrary files such as startup code and the main application
35
-
36
- The [packlets-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/other/packlets-tutorial) sample project illustrates this layout in full detail.
37
-
38
- The basic design can be summarized in 5 rules:
39
-
40
- 1. A "packlet" is defined to be a folder path `./src/packlets/<packlet-name>/index.ts`. The **index.ts** file will have the exported APIs. The `<packlet-name>` name must consist of lower case words separated by hyphens, similar to an NPM package name.
41
-
42
- Example file paths:
43
- ```
44
- src/packlets/controls
45
- src/packlets/logger
46
- src/packlets/my-long-name
47
- ```
48
-
49
- > **NOTE:** The `packlets` cannot be nested deeper in the tree. Like with NPM packages, `src/packlets` is a flat namespace.
50
-
51
- 2. Files outside the packlet folder can only import the packlet root **index.ts**:
52
-
53
- **src/app/App.ts**
54
- ```ts
55
- // Okay
56
- import { MainReport } from '../packlets/reports';
57
-
58
- // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
59
- import { MainReport } from '../packlets/reports/index';
60
-
61
- // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
62
- import { MainReport } from '../packlets/reports/MainReport';
63
- ```
64
-
65
- 3. Files inside a packlet folder should import their siblings directly, not via their own **index.ts** (which might create a circular reference):
66
-
67
- **src/packlets/logging/Logger.ts**
68
- ```ts
69
- // Okay
70
- import { MessageType } from "./MessageType";
71
-
72
- // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
73
- import { MessageType } from ".";
74
-
75
- // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
76
- import { MessageType} from "./index";
77
- ```
78
-
79
-
80
- 4. Packlets may reference other packlets, but not in a way that would introduce a circular dependency:
81
-
82
- **src/packlets/data-model/DataModel.ts**
83
- ```ts
84
- // Okay
85
- import { Logger } from '../../packlets/logging';
86
- ```
87
-
88
- **src/packlets/logging/Logger.ts**
89
- ```ts
90
- // Error: Packlet imports create a circular reference: (@rushstack/packlets/circular-deps)
91
- // "logging" is referenced by src/packlets/data-model/DataModel.ts
92
- // "data-model" is referenced by src/packlets/logging/Logger.ts
93
- import { DataModel } from '../../packlets/data-model';
94
- ```
95
-
96
- 5. Other source files are allowed outside the **src/packlets** folder. They may import a packlet, but packlets must only import from other packlets or NPM packages.
97
-
98
- **src/app/App.ts**
99
-
100
- ```ts
101
- // Okay
102
- import { MainReport } from '../packlets/reports';
103
- ```
104
-
105
- **src/packlets/data-model/ExampleModel.ts**
106
- ```ts
107
- // Error: A local project file cannot be imported. A packlet's dependencies must be
108
- // NPM packages and/or other packlets. (@rushstack/packlets/mechanics)
109
- import { App } from '../../app/App';
110
- ```
111
-
112
-
113
- ## Getting Started
114
-
115
- To enable packlet validation for a simple `typescript-eslint` setup, reference the `@rushstack/eslint-plugin-packlets` project like this:
116
-
117
- **\<my-project\>/.eslintrc.js**
118
- ```js
119
- module.exports = {
120
- root: true,
121
- parser: '@typescript-eslint/parser',
122
- plugins: ['@typescript-eslint'],
123
- extends: [
124
- 'eslint:recommended',
125
- 'plugin:@typescript-eslint/recommended',
126
- 'plugin:@rushstack/eslint-plugin-packlets/recommended' // <--- ADD THIS
127
- ],
128
- parserOptions: {
129
- project: './tsconfig.json',
130
- sourceType: 'module',
131
- tsconfigRootDir: __dirname
132
- }
133
- };
134
- ```
135
-
136
- Or, if you are using the [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) ruleset, add the `"packlets"` mixin like this:
137
-
138
- **\<my-project\>/.eslintrc.js**
139
- ```ts
140
- // This is a workaround for https://github.com/eslint/eslint/issues/3458
141
- require('@rushstack/eslint-config/patch/modern-module-resolution');
142
-
143
- module.exports = {
144
- extends: [
145
- "@rushstack/eslint-config/profile/node",
146
- "@rushstack/eslint-config/mixins/packlets" // <--- ADD THIS
147
- ],
148
- parserOptions: { tsconfigRootDir: __dirname }
149
- };
150
- ```
151
-
152
- The `@rushstack/eslint-plugin-packlets` plugin implements three separate rules:
153
-
154
- - `@rushstack/packlets/mechanics` - validates most of the import path rules outlined above.
155
- - `@rushstack/packlets/circular-deps` - detects circular dependencies between packlets. This rule requires an ESLint configuration that enables full type information from the TypeScript compiler.
156
- - `@rushstack/packlets/readme` - requires each packlet to have a README.md file. This rule is disabled by default.
157
-
158
- ## Requiring a README.md file
159
-
160
- If you'd like to require a README.md file in each packlet folder, enable the optional `@rushstack/packlets/readme` rule.
161
-
162
- The `minimumReadmeWords` option allows you to specify a minimum number of words of documentation in the README.md file. The default value is `10` words.
163
-
164
- Example configuration with the `@rushstack/packlets/readme` rule enabled:
165
-
166
- **\<my-project\>/.eslintrc.js**
167
- ```ts
168
- // This is a workaround for https://github.com/eslint/eslint/issues/3458
169
- require('@rushstack/eslint-config/patch/modern-module-resolution');
170
-
171
- module.exports = {
172
- extends: [
173
- "@rushstack/eslint-config/profile/node",
174
- "@rushstack/eslint-config/mixins/packlets"
175
- ],
176
- parserOptions: { tsconfigRootDir: __dirname },
177
- overrides: [
178
- {
179
- files: ['*.ts', '*.tsx'],
180
-
181
- rules: {
182
- '@rushstack/packlets/readme': [ // <--- ADD THIS
183
- 'warn',
184
- { minimumReadmeWords: 10 }
185
- ]
186
- }
187
- }
188
- ]
189
- };
190
- ```
191
-
192
- ## Links
193
-
194
- - [CHANGELOG.md](
195
- https://github.com/microsoft/rushstack/blob/master/stack/eslint-plugin-packlets/CHANGELOG.md) - Find
196
- out what's new in the latest version
197
- - [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) documentation
198
-
199
- `@rushstack/eslint-plugin-packlets` is part of the [Rush Stack](https://rushstack.io/) family of projects.
200
- The idea for packlets was originally proposed by [@bartvandenende-wm](https://github.com/bartvandenende-wm)
201
- and [@victor-wm](https://github.com/victor-wm).
1
+ # @rushstack/eslint-plugin-packlets
2
+
3
+ Packlets provide a lightweight alternative to NPM packages for organizing source files within a single project. The formalism is validated using ESLint rules.
4
+
5
+ ## Motivation
6
+
7
+ When building a large application, it's a good idea to organize source files into modules, so that their dependencies can be managed. For example, suppose an application's source files can be grouped as follows:
8
+
9
+ - `src/logging/*.ts` - the logging system
10
+ - `src/data-model/*.ts` - the data model
11
+ - `src/reports/*.ts` - the report engine
12
+ - `src/*.ts` - other arbitrary files such as startup code and the main application
13
+
14
+ Using file folders is helpful, but it's not very strict. Files under `src/logging` can easily import files from `/src/reports`, creating a confusing circular import. They can also import arbitrary application files. Also, there is no clear distinction between which files are the "public API" for `src/logging` versus its private implementation details.
15
+
16
+ All these problems can be solved by reorganizing the project into NPM packages (or [Rush projects](https://rushjs.io/)). Something like this:
17
+
18
+ - `@my-app/logging` - the logging system
19
+ - `@my-app/data-model` - the data model
20
+ - `@my-app/reports` - the report engine
21
+ - `@my-app/application` - other arbitrary files such as startup code and the main application
22
+
23
+ However, separating code in this way has some downsides. The projects need to build separately, which has some tooling costs (for example, "watch mode" now needs to consider multiple projects). In a large monorepo, the library may attract other consumers, before the API has been fully worked out.
24
+
25
+ Packlets provide a lightweight alternative that offers many of the same benefits of packages, but without the `package.json` file. It's a great way to prototype your project organization before later graduating your packlets into proper NPM packages.
26
+
27
+ ## 5 rules for packlets
28
+
29
+ With packlets, our folders would be reorganized as follows:
30
+
31
+ - `src/packlets/logging/*.ts` - the logging system
32
+ - `src/packlets/data-model/*.ts` - the data model
33
+ - `src/packlets/reports/*.ts` - the report engine
34
+ - `src/*.ts` - other arbitrary files such as startup code and the main application
35
+
36
+ The [packlets-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/other/packlets-tutorial) sample project illustrates this layout in full detail.
37
+
38
+ The basic design can be summarized in 5 rules:
39
+
40
+ 1. A "packlet" is defined to be a folder path `./src/packlets/<packlet-name>/index.ts`. The **index.ts** file will have the exported APIs. The `<packlet-name>` name must consist of lower case words separated by hyphens, similar to an NPM package name.
41
+
42
+ Example file paths:
43
+ ```
44
+ src/packlets/controls
45
+ src/packlets/logger
46
+ src/packlets/my-long-name
47
+ ```
48
+
49
+ > **NOTE:** The `packlets` cannot be nested deeper in the tree. Like with NPM packages, `src/packlets` is a flat namespace.
50
+
51
+ 2. Files outside the packlet folder can only import the packlet root **index.ts**:
52
+
53
+ **src/app/App.ts**
54
+ ```ts
55
+ // Okay
56
+ import { MainReport } from '../packlets/reports';
57
+
58
+ // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
59
+ import { MainReport } from '../packlets/reports/index';
60
+
61
+ // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
62
+ import { MainReport } from '../packlets/reports/MainReport';
63
+ ```
64
+
65
+ 3. Files inside a packlet folder should import their siblings directly, not via their own **index.ts** (which might create a circular reference):
66
+
67
+ **src/packlets/logging/Logger.ts**
68
+ ```ts
69
+ // Okay
70
+ import { MessageType } from "./MessageType";
71
+
72
+ // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
73
+ import { MessageType } from ".";
74
+
75
+ // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
76
+ import { MessageType} from "./index";
77
+ ```
78
+
79
+
80
+ 4. Packlets may reference other packlets, but not in a way that would introduce a circular dependency:
81
+
82
+ **src/packlets/data-model/DataModel.ts**
83
+ ```ts
84
+ // Okay
85
+ import { Logger } from '../../packlets/logging';
86
+ ```
87
+
88
+ **src/packlets/logging/Logger.ts**
89
+ ```ts
90
+ // Error: Packlet imports create a circular reference: (@rushstack/packlets/circular-deps)
91
+ // "logging" is referenced by src/packlets/data-model/DataModel.ts
92
+ // "data-model" is referenced by src/packlets/logging/Logger.ts
93
+ import { DataModel } from '../../packlets/data-model';
94
+ ```
95
+
96
+ 5. Other source files are allowed outside the **src/packlets** folder. They may import a packlet, but packlets must only import from other packlets or NPM packages.
97
+
98
+ **src/app/App.ts**
99
+
100
+ ```ts
101
+ // Okay
102
+ import { MainReport } from '../packlets/reports';
103
+ ```
104
+
105
+ **src/packlets/data-model/ExampleModel.ts**
106
+ ```ts
107
+ // Error: A local project file cannot be imported. A packlet's dependencies must be
108
+ // NPM packages and/or other packlets. (@rushstack/packlets/mechanics)
109
+ import { App } from '../../app/App';
110
+ ```
111
+
112
+
113
+ ## Getting Started
114
+
115
+ To enable packlet validation for a simple `typescript-eslint` setup, reference the `@rushstack/eslint-plugin-packlets` project like this:
116
+
117
+ **\<my-project\>/.eslintrc.js**
118
+ ```js
119
+ module.exports = {
120
+ root: true,
121
+ parser: '@typescript-eslint/parser',
122
+ plugins: ['@typescript-eslint'],
123
+ extends: [
124
+ 'eslint:recommended',
125
+ 'plugin:@typescript-eslint/recommended',
126
+ 'plugin:@rushstack/eslint-plugin-packlets/recommended' // <--- ADD THIS
127
+ ],
128
+ parserOptions: {
129
+ project: './tsconfig.json',
130
+ sourceType: 'module',
131
+ tsconfigRootDir: __dirname
132
+ }
133
+ };
134
+ ```
135
+
136
+ Or, if you are using the [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) ruleset, add the `"packlets"` mixin like this:
137
+
138
+ **\<my-project\>/.eslintrc.js**
139
+ ```ts
140
+ // This is a workaround for https://github.com/eslint/eslint/issues/3458
141
+ require('@rushstack/eslint-config/patch/modern-module-resolution');
142
+
143
+ module.exports = {
144
+ extends: [
145
+ "@rushstack/eslint-config/profile/node",
146
+ "@rushstack/eslint-config/mixins/packlets" // <--- ADD THIS
147
+ ],
148
+ parserOptions: { tsconfigRootDir: __dirname }
149
+ };
150
+ ```
151
+
152
+ The `@rushstack/eslint-plugin-packlets` plugin implements three separate rules:
153
+
154
+ - `@rushstack/packlets/mechanics` - validates most of the import path rules outlined above.
155
+ - `@rushstack/packlets/circular-deps` - detects circular dependencies between packlets. This rule requires an ESLint configuration that enables full type information from the TypeScript compiler.
156
+ - `@rushstack/packlets/readme` - requires each packlet to have a README.md file. This rule is disabled by default.
157
+
158
+ ## Requiring a README.md file
159
+
160
+ If you'd like to require a README.md file in each packlet folder, enable the optional `@rushstack/packlets/readme` rule.
161
+
162
+ The `minimumReadmeWords` option allows you to specify a minimum number of words of documentation in the README.md file. The default value is `10` words.
163
+
164
+ Example configuration with the `@rushstack/packlets/readme` rule enabled:
165
+
166
+ **\<my-project\>/.eslintrc.js**
167
+ ```ts
168
+ // This is a workaround for https://github.com/eslint/eslint/issues/3458
169
+ require('@rushstack/eslint-config/patch/modern-module-resolution');
170
+
171
+ module.exports = {
172
+ extends: [
173
+ "@rushstack/eslint-config/profile/node",
174
+ "@rushstack/eslint-config/mixins/packlets"
175
+ ],
176
+ parserOptions: { tsconfigRootDir: __dirname },
177
+ overrides: [
178
+ {
179
+ files: ['*.ts', '*.tsx'],
180
+
181
+ rules: {
182
+ '@rushstack/packlets/readme': [ // <--- ADD THIS
183
+ 'warn',
184
+ { minimumReadmeWords: 10 }
185
+ ]
186
+ }
187
+ }
188
+ ]
189
+ };
190
+ ```
191
+
192
+ ## Links
193
+
194
+ - [CHANGELOG.md](
195
+ https://github.com/microsoft/rushstack/blob/master/stack/eslint-plugin-packlets/CHANGELOG.md) - Find
196
+ out what's new in the latest version
197
+ - [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) documentation
198
+
199
+ `@rushstack/eslint-plugin-packlets` is part of the [Rush Stack](https://rushstack.io/) family of projects.
200
+ The idea for packlets was originally proposed by [@bartvandenende-wm](https://github.com/bartvandenende-wm)
201
+ and [@victor-wm](https://github.com/victor-wm).
@@ -1 +1 @@
1
- {"version":3,"file":"DependencyAnalyzer.js","sourceRoot":"","sources":["../src/DependencyAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport type * as ts from 'typescript';\r\n\r\nimport { Path } from './Path';\r\nimport { PackletAnalyzer } from './PackletAnalyzer';\r\n\r\nenum RefFileKind {\r\n Import,\r\n ReferenceFile,\r\n TypeReferenceDirective\r\n}\r\n\r\n// TypeScript compiler internal:\r\n// Version range: >= 3.6.0, <= 4.2.0\r\n// https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/program.ts#L541\r\ninterface RefFile {\r\n // The absolute path of the module that was imported.\r\n // (Normalized to an all lowercase ts.Path string.)\r\n referencedFileName: string;\r\n // The kind of reference.\r\n kind: RefFileKind;\r\n // An index indicating the order in which items occur in a compound expression\r\n index: number;\r\n\r\n // The absolute path of the source file containing the import statement.\r\n // (Normalized to an all lowercase ts.Path string.)\r\n file: string;\r\n}\r\n\r\n// TypeScript compiler internal:\r\n// Version range: > 4.2.0\r\n// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3693\r\nenum FileIncludeKind {\r\n RootFile,\r\n SourceFromProjectReference,\r\n OutputFromProjectReference,\r\n Import,\r\n ReferenceFile,\r\n TypeReferenceDirective,\r\n LibFile,\r\n LibReferenceDirective,\r\n AutomaticTypeDirectiveFile\r\n}\r\n\r\n// TypeScript compiler internal:\r\n// Version range: > 4.2.0\r\n// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3748\r\ntype FileIncludeReason = {\r\n kind: FileIncludeKind;\r\n file: string | undefined;\r\n};\r\n\r\ninterface ITsProgramInternals extends ts.Program {\r\n // TypeScript compiler internal:\r\n // Version range: >= 3.6.0, <= 4.2.0\r\n // https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/types.ts#L3723\r\n getRefFileMap?: () => Map<string, RefFile[]> | undefined;\r\n\r\n // TypeScript compiler internal:\r\n // Version range: > 4.2.0\r\n // https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3871\r\n getFileIncludeReasons?: () => Map<string, FileIncludeReason[]>;\r\n}\r\n\r\n/**\r\n * Represents a packlet that imports another packlet.\r\n */\r\nexport interface IPackletImport {\r\n /**\r\n * The name of the packlet being imported.\r\n */\r\n packletName: string;\r\n\r\n /**\r\n * The absolute path of the file that imports the packlet.\r\n */\r\n fromFilePath: string;\r\n}\r\n\r\n/**\r\n * Used to build a linked list of imports that represent a circular dependency.\r\n */\r\ninterface IImportListNode extends IPackletImport {\r\n /**\r\n * The previous link in the linked list.\r\n */\r\n previousNode: IImportListNode | undefined;\r\n}\r\n\r\nexport class DependencyAnalyzer {\r\n /**\r\n * @param packletName - the packlet to be checked next in our traversal\r\n * @param startingPackletName - the packlet that we started with; if the traversal reaches this packlet,\r\n * then a circular dependency has been detected\r\n * @param refFileMap - the compiler's `refFileMap` data structure describing import relationships\r\n * @param fileIncludeReasonsMap - the compiler's data structure describing import relationships\r\n * @param program - the compiler's `ts.Program` object\r\n * @param packletsFolderPath - the absolute path of the \"src/packlets\" folder.\r\n * @param visitedPacklets - the set of packlets that have already been visited in this traversal\r\n * @param previousNode - a linked list of import statements that brought us to this step in the traversal\r\n */\r\n private static _walkImports(\r\n packletName: string,\r\n startingPackletName: string,\r\n refFileMap: Map<string, RefFile[]> | undefined,\r\n fileIncludeReasonsMap: Map<string, FileIncludeReason[]> | undefined,\r\n program: ts.Program,\r\n packletsFolderPath: string,\r\n visitedPacklets: Set<string>,\r\n previousNode: IImportListNode | undefined\r\n ): IImportListNode | undefined {\r\n visitedPacklets.add(packletName);\r\n\r\n const packletEntryPoint: string = Path.join(packletsFolderPath, packletName, 'index');\r\n\r\n const tsSourceFile: ts.SourceFile | undefined =\r\n program.getSourceFile(packletEntryPoint + '.ts') || program.getSourceFile(packletEntryPoint + '.tsx');\r\n if (!tsSourceFile) {\r\n return undefined;\r\n }\r\n\r\n const referencingFilePaths: string[] = [];\r\n\r\n if (refFileMap) {\r\n // TypeScript version range: >= 3.6.0, <= 4.2.0\r\n const refFiles: RefFile[] | undefined = refFileMap.get((tsSourceFile as any).path as any);\r\n if (refFiles) {\r\n for (const refFile of refFiles) {\r\n if (refFile.kind === RefFileKind.Import) {\r\n referencingFilePaths.push(refFile.file);\r\n }\r\n }\r\n }\r\n } else if (fileIncludeReasonsMap) {\r\n // Typescript version range: > 4.2.0\r\n const fileIncludeReasons: FileIncludeReason[] | undefined = fileIncludeReasonsMap.get(\r\n (tsSourceFile as any).path as any\r\n );\r\n if (fileIncludeReasons) {\r\n for (const fileIncludeReason of fileIncludeReasons) {\r\n if (fileIncludeReason.kind === FileIncludeKind.Import) {\r\n if (fileIncludeReason.file) {\r\n referencingFilePaths.push(fileIncludeReason.file);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n for (const referencingFilePath of referencingFilePaths) {\r\n // Is it a reference to a packlet?\r\n if (Path.isUnder(referencingFilePath, packletsFolderPath)) {\r\n const referencingRelativePath: string = Path.relative(packletsFolderPath, referencingFilePath);\r\n const referencingPathParts: string[] = referencingRelativePath.split(/[\\/\\\\]+/);\r\n const referencingPackletName: string = referencingPathParts[0];\r\n\r\n // Did we return to where we started from?\r\n if (referencingPackletName === startingPackletName) {\r\n // Ignore the degenerate case where the starting node imports itself,\r\n // since @rushstack/packlets/mechanics will already report that.\r\n if (previousNode) {\r\n // Make a new linked list node to record this step of the traversal\r\n const importListNode: IImportListNode = {\r\n previousNode: previousNode,\r\n fromFilePath: referencingFilePath,\r\n packletName: packletName\r\n };\r\n\r\n // The traversal has returned to the packlet that we started from;\r\n // this means we have detected a circular dependency\r\n return importListNode;\r\n }\r\n }\r\n\r\n // Have we already analyzed this packlet?\r\n if (!visitedPacklets.has(referencingPackletName)) {\r\n // Make a new linked list node to record this step of the traversal\r\n const importListNode: IImportListNode = {\r\n previousNode: previousNode,\r\n fromFilePath: referencingFilePath,\r\n packletName: packletName\r\n };\r\n\r\n const result: IImportListNode | undefined = DependencyAnalyzer._walkImports(\r\n referencingPackletName,\r\n startingPackletName,\r\n refFileMap,\r\n fileIncludeReasonsMap,\r\n program,\r\n packletsFolderPath,\r\n visitedPacklets,\r\n importListNode\r\n );\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n /**\r\n * For the specified packlet, trace all modules that import it, looking for a circular dependency\r\n * between packlets. If found, an array is returned describing the import statements that cause\r\n * the problem.\r\n *\r\n * @remarks\r\n * For example, suppose we have files like this:\r\n *\r\n * ```\r\n * src/packlets/logging/index.ts\r\n * src/packlets/logging/Logger.ts --> imports \"../data-model\"\r\n * src/packlets/data-model/index.ts\r\n * src/packlets/data-model/DataModel.ts --> imports \"../logging\"\r\n * ```\r\n *\r\n * The returned array would be:\r\n * ```ts\r\n * [\r\n * { packletName: \"logging\", fromFilePath: \"/path/to/src/packlets/data-model/DataModel.ts\" },\r\n * { packletName: \"data-model\", fromFilePath: \"/path/to/src/packlets/logging/Logger.ts\" },\r\n * ]\r\n * ```\r\n *\r\n * If there is more than one circular dependency chain, only the first one that is encountered\r\n * will be returned.\r\n */\r\n public static checkEntryPointForCircularImport(\r\n packletName: string,\r\n packletAnalyzer: PackletAnalyzer,\r\n program: ts.Program\r\n ): IPackletImport[] | undefined {\r\n const programInternals: ITsProgramInternals = program;\r\n\r\n let refFileMap: Map<string, RefFile[]> | undefined;\r\n let fileIncludeReasonsMap: Map<string, FileIncludeReason[]> | undefined;\r\n\r\n if (programInternals.getRefFileMap) {\r\n // TypeScript version range: >= 3.6.0, <= 4.2.0\r\n refFileMap = programInternals.getRefFileMap();\r\n } else if (programInternals.getFileIncludeReasons) {\r\n // Typescript version range: > 4.2.0\r\n fileIncludeReasonsMap = programInternals.getFileIncludeReasons();\r\n } else {\r\n // If you encounter this error, please report a bug\r\n throw new Error(\r\n 'Your TypeScript compiler version is not supported; please upgrade @rushstack/eslint-plugin-packlets' +\r\n ' or report a GitHub issue'\r\n );\r\n }\r\n\r\n const visitedPacklets: Set<string> = new Set();\r\n\r\n const listNode: IImportListNode | undefined = DependencyAnalyzer._walkImports(\r\n packletName,\r\n packletName,\r\n refFileMap,\r\n fileIncludeReasonsMap,\r\n program,\r\n packletAnalyzer.packletsFolderPath!,\r\n visitedPacklets,\r\n undefined // previousNode\r\n );\r\n\r\n if (listNode) {\r\n // Convert the linked list to an array\r\n const packletImports: IPackletImport[] = [];\r\n for (let current: IImportListNode | undefined = listNode; current; current = current.previousNode) {\r\n packletImports.push({ fromFilePath: current.fromFilePath, packletName: current.packletName });\r\n }\r\n return packletImports;\r\n }\r\n\r\n return undefined;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"DependencyAnalyzer.js","sourceRoot":"","sources":["../src/DependencyAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as ts from 'typescript';\n\nimport { Path } from './Path';\nimport { PackletAnalyzer } from './PackletAnalyzer';\n\nenum RefFileKind {\n Import,\n ReferenceFile,\n TypeReferenceDirective\n}\n\n// TypeScript compiler internal:\n// Version range: >= 3.6.0, <= 4.2.0\n// https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/program.ts#L541\ninterface RefFile {\n // The absolute path of the module that was imported.\n // (Normalized to an all lowercase ts.Path string.)\n referencedFileName: string;\n // The kind of reference.\n kind: RefFileKind;\n // An index indicating the order in which items occur in a compound expression\n index: number;\n\n // The absolute path of the source file containing the import statement.\n // (Normalized to an all lowercase ts.Path string.)\n file: string;\n}\n\n// TypeScript compiler internal:\n// Version range: > 4.2.0\n// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3693\nenum FileIncludeKind {\n RootFile,\n SourceFromProjectReference,\n OutputFromProjectReference,\n Import,\n ReferenceFile,\n TypeReferenceDirective,\n LibFile,\n LibReferenceDirective,\n AutomaticTypeDirectiveFile\n}\n\n// TypeScript compiler internal:\n// Version range: > 4.2.0\n// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3748\ntype FileIncludeReason = {\n kind: FileIncludeKind;\n file: string | undefined;\n};\n\ninterface ITsProgramInternals extends ts.Program {\n // TypeScript compiler internal:\n // Version range: >= 3.6.0, <= 4.2.0\n // https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/types.ts#L3723\n getRefFileMap?: () => Map<string, RefFile[]> | undefined;\n\n // TypeScript compiler internal:\n // Version range: > 4.2.0\n // https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3871\n getFileIncludeReasons?: () => Map<string, FileIncludeReason[]>;\n}\n\n/**\n * Represents a packlet that imports another packlet.\n */\nexport interface IPackletImport {\n /**\n * The name of the packlet being imported.\n */\n packletName: string;\n\n /**\n * The absolute path of the file that imports the packlet.\n */\n fromFilePath: string;\n}\n\n/**\n * Used to build a linked list of imports that represent a circular dependency.\n */\ninterface IImportListNode extends IPackletImport {\n /**\n * The previous link in the linked list.\n */\n previousNode: IImportListNode | undefined;\n}\n\nexport class DependencyAnalyzer {\n /**\n * @param packletName - the packlet to be checked next in our traversal\n * @param startingPackletName - the packlet that we started with; if the traversal reaches this packlet,\n * then a circular dependency has been detected\n * @param refFileMap - the compiler's `refFileMap` data structure describing import relationships\n * @param fileIncludeReasonsMap - the compiler's data structure describing import relationships\n * @param program - the compiler's `ts.Program` object\n * @param packletsFolderPath - the absolute path of the \"src/packlets\" folder.\n * @param visitedPacklets - the set of packlets that have already been visited in this traversal\n * @param previousNode - a linked list of import statements that brought us to this step in the traversal\n */\n private static _walkImports(\n packletName: string,\n startingPackletName: string,\n refFileMap: Map<string, RefFile[]> | undefined,\n fileIncludeReasonsMap: Map<string, FileIncludeReason[]> | undefined,\n program: ts.Program,\n packletsFolderPath: string,\n visitedPacklets: Set<string>,\n previousNode: IImportListNode | undefined\n ): IImportListNode | undefined {\n visitedPacklets.add(packletName);\n\n const packletEntryPoint: string = Path.join(packletsFolderPath, packletName, 'index');\n\n const tsSourceFile: ts.SourceFile | undefined =\n program.getSourceFile(packletEntryPoint + '.ts') || program.getSourceFile(packletEntryPoint + '.tsx');\n if (!tsSourceFile) {\n return undefined;\n }\n\n const referencingFilePaths: string[] = [];\n\n if (refFileMap) {\n // TypeScript version range: >= 3.6.0, <= 4.2.0\n const refFiles: RefFile[] | undefined = refFileMap.get((tsSourceFile as any).path as any);\n if (refFiles) {\n for (const refFile of refFiles) {\n if (refFile.kind === RefFileKind.Import) {\n referencingFilePaths.push(refFile.file);\n }\n }\n }\n } else if (fileIncludeReasonsMap) {\n // Typescript version range: > 4.2.0\n const fileIncludeReasons: FileIncludeReason[] | undefined = fileIncludeReasonsMap.get(\n (tsSourceFile as any).path as any\n );\n if (fileIncludeReasons) {\n for (const fileIncludeReason of fileIncludeReasons) {\n if (fileIncludeReason.kind === FileIncludeKind.Import) {\n if (fileIncludeReason.file) {\n referencingFilePaths.push(fileIncludeReason.file);\n }\n }\n }\n }\n }\n\n for (const referencingFilePath of referencingFilePaths) {\n // Is it a reference to a packlet?\n if (Path.isUnder(referencingFilePath, packletsFolderPath)) {\n const referencingRelativePath: string = Path.relative(packletsFolderPath, referencingFilePath);\n const referencingPathParts: string[] = referencingRelativePath.split(/[\\/\\\\]+/);\n const referencingPackletName: string = referencingPathParts[0];\n\n // Did we return to where we started from?\n if (referencingPackletName === startingPackletName) {\n // Ignore the degenerate case where the starting node imports itself,\n // since @rushstack/packlets/mechanics will already report that.\n if (previousNode) {\n // Make a new linked list node to record this step of the traversal\n const importListNode: IImportListNode = {\n previousNode: previousNode,\n fromFilePath: referencingFilePath,\n packletName: packletName\n };\n\n // The traversal has returned to the packlet that we started from;\n // this means we have detected a circular dependency\n return importListNode;\n }\n }\n\n // Have we already analyzed this packlet?\n if (!visitedPacklets.has(referencingPackletName)) {\n // Make a new linked list node to record this step of the traversal\n const importListNode: IImportListNode = {\n previousNode: previousNode,\n fromFilePath: referencingFilePath,\n packletName: packletName\n };\n\n const result: IImportListNode | undefined = DependencyAnalyzer._walkImports(\n referencingPackletName,\n startingPackletName,\n refFileMap,\n fileIncludeReasonsMap,\n program,\n packletsFolderPath,\n visitedPacklets,\n importListNode\n );\n if (result) {\n return result;\n }\n }\n }\n }\n\n return undefined;\n }\n\n /**\n * For the specified packlet, trace all modules that import it, looking for a circular dependency\n * between packlets. If found, an array is returned describing the import statements that cause\n * the problem.\n *\n * @remarks\n * For example, suppose we have files like this:\n *\n * ```\n * src/packlets/logging/index.ts\n * src/packlets/logging/Logger.ts --> imports \"../data-model\"\n * src/packlets/data-model/index.ts\n * src/packlets/data-model/DataModel.ts --> imports \"../logging\"\n * ```\n *\n * The returned array would be:\n * ```ts\n * [\n * { packletName: \"logging\", fromFilePath: \"/path/to/src/packlets/data-model/DataModel.ts\" },\n * { packletName: \"data-model\", fromFilePath: \"/path/to/src/packlets/logging/Logger.ts\" },\n * ]\n * ```\n *\n * If there is more than one circular dependency chain, only the first one that is encountered\n * will be returned.\n */\n public static checkEntryPointForCircularImport(\n packletName: string,\n packletAnalyzer: PackletAnalyzer,\n program: ts.Program\n ): IPackletImport[] | undefined {\n const programInternals: ITsProgramInternals = program;\n\n let refFileMap: Map<string, RefFile[]> | undefined;\n let fileIncludeReasonsMap: Map<string, FileIncludeReason[]> | undefined;\n\n if (programInternals.getRefFileMap) {\n // TypeScript version range: >= 3.6.0, <= 4.2.0\n refFileMap = programInternals.getRefFileMap();\n } else if (programInternals.getFileIncludeReasons) {\n // Typescript version range: > 4.2.0\n fileIncludeReasonsMap = programInternals.getFileIncludeReasons();\n } else {\n // If you encounter this error, please report a bug\n throw new Error(\n 'Your TypeScript compiler version is not supported; please upgrade @rushstack/eslint-plugin-packlets' +\n ' or report a GitHub issue'\n );\n }\n\n const visitedPacklets: Set<string> = new Set();\n\n const listNode: IImportListNode | undefined = DependencyAnalyzer._walkImports(\n packletName,\n packletName,\n refFileMap,\n fileIncludeReasonsMap,\n program,\n packletAnalyzer.packletsFolderPath!,\n visitedPacklets,\n undefined // previousNode\n );\n\n if (listNode) {\n // Convert the linked list to an array\n const packletImports: IPackletImport[] = [];\n for (let current: IImportListNode | undefined = listNode; current; current = current.previousNode) {\n packletImports.push({ fromFilePath: current.fromFilePath, packletName: current.packletName });\n }\n return packletImports;\n }\n\n return undefined;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackletAnalyzer.js","sourceRoot":"","sources":["../src/PackletAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport * as fs from 'fs';\r\nimport { Path } from './Path';\r\n\r\nexport type InputFileMessageIds =\r\n | 'file-in-packets-folder'\r\n | 'invalid-packlet-name'\r\n | 'misplaced-packlets-folder'\r\n | 'missing-src-folder'\r\n | 'missing-tsconfig'\r\n | 'packlet-folder-case';\r\n\r\nexport type ImportMessageIds =\r\n | 'bypassed-entry-point'\r\n | 'circular-entry-point'\r\n | 'packlet-importing-project-file';\r\n\r\nexport interface IAnalyzerError {\r\n messageId: InputFileMessageIds | ImportMessageIds;\r\n data?: Readonly<Record<string, unknown>>;\r\n}\r\n\r\nexport class PackletAnalyzer {\r\n private static _validPackletName: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/;\r\n\r\n /**\r\n * The input file being linted.\r\n *\r\n * Example: \"/path/to/my-project/src/file.ts\"\r\n */\r\n public readonly inputFilePath: string;\r\n\r\n /**\r\n * An error that occurred while analyzing the inputFilePath.\r\n */\r\n public readonly error: IAnalyzerError | undefined;\r\n\r\n /**\r\n * Returned to indicate that the linter can ignore this file. Possible reasons:\r\n * - It's outside the \"src\" folder\r\n * - The project doesn't define any packlets\r\n */\r\n public readonly nothingToDo: boolean;\r\n\r\n /**\r\n * If true, then the \"src/packlets\" folder exists.\r\n */\r\n public readonly projectUsesPacklets: boolean;\r\n\r\n /**\r\n * The absolute path of the \"src/packlets\" folder.\r\n */\r\n public readonly packletsFolderPath: string | undefined;\r\n\r\n /**\r\n * The packlet that the inputFilePath is under, if any.\r\n */\r\n public readonly inputFilePackletName: string | undefined;\r\n\r\n /**\r\n * Returns true if inputFilePath belongs to a packlet and is the entry point index.ts.\r\n */\r\n public readonly isEntryPoint: boolean;\r\n\r\n private constructor(inputFilePath: string, tsconfigFilePath: string | undefined) {\r\n this.inputFilePath = inputFilePath;\r\n this.error = undefined;\r\n this.nothingToDo = false;\r\n this.projectUsesPacklets = false;\r\n this.packletsFolderPath = undefined;\r\n this.inputFilePackletName = undefined;\r\n this.isEntryPoint = false;\r\n\r\n // Example: /path/to/my-project/src\r\n let srcFolderPath: string | undefined;\r\n\r\n if (!tsconfigFilePath) {\r\n this.error = { messageId: 'missing-tsconfig' };\r\n return;\r\n }\r\n\r\n srcFolderPath = Path.join(Path.dirname(tsconfigFilePath), 'src');\r\n\r\n if (!fs.existsSync(srcFolderPath)) {\r\n this.error = { messageId: 'missing-src-folder', data: { srcFolderPath } };\r\n return;\r\n }\r\n\r\n if (!Path.isUnder(inputFilePath, srcFolderPath)) {\r\n // Ignore files outside the \"src\" folder\r\n this.nothingToDo = true;\r\n return;\r\n }\r\n\r\n // Example: packlets/my-packlet/index.ts\r\n const inputFilePathRelativeToSrc: string = Path.relative(srcFolderPath, inputFilePath);\r\n\r\n // Example: [ 'packlets', 'my-packlet', 'index.ts' ]\r\n const pathParts: string[] = inputFilePathRelativeToSrc.split(/[\\/\\\\]+/);\r\n\r\n let underPackletsFolder: boolean = false;\r\n\r\n const expectedPackletsFolder: string = Path.join(srcFolderPath, 'packlets');\r\n\r\n for (let i = 0; i < pathParts.length; ++i) {\r\n const pathPart: string = pathParts[i];\r\n if (pathPart.toUpperCase() === 'PACKLETS') {\r\n if (pathPart !== 'packlets') {\r\n // Example: /path/to/my-project/src/PACKLETS\r\n const packletsFolderPath: string = Path.join(srcFolderPath, ...pathParts.slice(0, i + 1));\r\n this.error = { messageId: 'packlet-folder-case', data: { packletsFolderPath } };\r\n return;\r\n }\r\n\r\n if (i !== 0) {\r\n this.error = { messageId: 'misplaced-packlets-folder', data: { expectedPackletsFolder } };\r\n return;\r\n }\r\n\r\n underPackletsFolder = true;\r\n }\r\n }\r\n\r\n if (underPackletsFolder || fs.existsSync(expectedPackletsFolder)) {\r\n // packletsAbsolutePath\r\n this.projectUsesPacklets = true;\r\n this.packletsFolderPath = expectedPackletsFolder;\r\n }\r\n\r\n if (underPackletsFolder) {\r\n if (pathParts.length === 2) {\r\n // Example: src/packlets/SomeFile.ts\r\n this.error = { messageId: 'file-in-packets-folder' };\r\n return;\r\n }\r\n if (pathParts.length >= 2) {\r\n // Example: 'my-packlet'\r\n const packletName: string = pathParts[1];\r\n this.inputFilePackletName = packletName;\r\n\r\n if (pathParts.length === 3) {\r\n // Example: 'index.ts' or 'index.tsx'\r\n const thirdPart: string = pathParts[2];\r\n\r\n // Example: 'index'\r\n const thirdPartWithoutExtension: string = Path.parse(thirdPart).name;\r\n\r\n if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') {\r\n if (!PackletAnalyzer._validPackletName.test(packletName)) {\r\n this.error = { messageId: 'invalid-packlet-name', data: { packletName } };\r\n return;\r\n }\r\n\r\n this.isEntryPoint = true;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (this.error === undefined && !this.projectUsesPacklets) {\r\n this.nothingToDo = true;\r\n }\r\n }\r\n\r\n public static analyzeInputFile(inputFilePath: string, tsconfigFilePath: string | undefined) {\r\n return new PackletAnalyzer(inputFilePath, tsconfigFilePath);\r\n }\r\n\r\n public analyzeImport(modulePath: string): IAnalyzerError | undefined {\r\n if (!this.packletsFolderPath) {\r\n // The caller should ensure this can never happen\r\n throw new Error('Internal error: packletsFolderPath is not defined');\r\n }\r\n\r\n // Example: /path/to/my-project/src/packlets/my-packlet\r\n const inputFileFolder: string = Path.dirname(this.inputFilePath);\r\n\r\n // Example: /path/to/my-project/src/other-packlet/index\r\n const importedPath: string = Path.resolve(inputFileFolder, modulePath);\r\n\r\n // Is the imported path referring to a file under the src/packlets folder?\r\n if (Path.isUnder(importedPath, this.packletsFolderPath)) {\r\n // Example: other-packlet/index\r\n const importedPathRelativeToPackletsFolder: string = Path.relative(\r\n this.packletsFolderPath,\r\n importedPath\r\n );\r\n // Example: [ 'other-packlet', 'index' ]\r\n const importedPathParts: string[] = importedPathRelativeToPackletsFolder.split(/[\\/\\\\]+/);\r\n if (importedPathParts.length > 0) {\r\n // Example: 'other-packlet'\r\n const importedPackletName: string = importedPathParts[0];\r\n\r\n // We are importing from a packlet. Is the input file part of the same packlet?\r\n if (this.inputFilePackletName && importedPackletName === this.inputFilePackletName) {\r\n // Yes. Then our import must NOT use the packlet entry point.\r\n\r\n // Example: 'index'\r\n //\r\n // We discard the file extension to handle a degenerate case like:\r\n // import { X } from \"../index.js\";\r\n const lastPart: string = Path.parse(importedPathParts[importedPathParts.length - 1]).name;\r\n let pathToCompare: string;\r\n if (lastPart.toUpperCase() === 'INDEX') {\r\n // Example:\r\n // importedPath = /path/to/my-project/src/other-packlet/index\r\n // pathToCompare = /path/to/my-project/src/other-packlet\r\n pathToCompare = Path.dirname(importedPath);\r\n } else {\r\n pathToCompare = importedPath;\r\n }\r\n\r\n // Example: /path/to/my-project/src/other-packlet\r\n const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName);\r\n\r\n if (Path.isEqual(pathToCompare, entryPointPath)) {\r\n return {\r\n messageId: 'circular-entry-point'\r\n };\r\n }\r\n } else {\r\n // No. If we are not part of the same packlet, then the module path must refer\r\n // to the index.ts entry point.\r\n\r\n // Example: /path/to/my-project/src/other-packlet\r\n const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName);\r\n\r\n if (!Path.isEqual(importedPath, entryPointPath)) {\r\n // Example: \"../packlets/other-packlet\"\r\n const entryPointModulePath: string = Path.convertToSlashes(\r\n Path.relative(inputFileFolder, entryPointPath)\r\n );\r\n\r\n return {\r\n messageId: 'bypassed-entry-point',\r\n data: { entryPointModulePath }\r\n };\r\n }\r\n }\r\n }\r\n } else {\r\n // The imported path does NOT refer to a file under the src/packlets folder\r\n if (this.inputFilePackletName) {\r\n return {\r\n messageId: 'packlet-importing-project-file'\r\n };\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"PackletAnalyzer.js","sourceRoot":"","sources":["../src/PackletAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as fs from 'fs';\nimport { Path } from './Path';\n\nexport type InputFileMessageIds =\n | 'file-in-packets-folder'\n | 'invalid-packlet-name'\n | 'misplaced-packlets-folder'\n | 'missing-src-folder'\n | 'missing-tsconfig'\n | 'packlet-folder-case';\n\nexport type ImportMessageIds =\n | 'bypassed-entry-point'\n | 'circular-entry-point'\n | 'packlet-importing-project-file';\n\nexport interface IAnalyzerError {\n messageId: InputFileMessageIds | ImportMessageIds;\n data?: Readonly<Record<string, unknown>>;\n}\n\nexport class PackletAnalyzer {\n private static _validPackletName: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/;\n\n /**\n * The input file being linted.\n *\n * Example: \"/path/to/my-project/src/file.ts\"\n */\n public readonly inputFilePath: string;\n\n /**\n * An error that occurred while analyzing the inputFilePath.\n */\n public readonly error: IAnalyzerError | undefined;\n\n /**\n * Returned to indicate that the linter can ignore this file. Possible reasons:\n * - It's outside the \"src\" folder\n * - The project doesn't define any packlets\n */\n public readonly nothingToDo: boolean;\n\n /**\n * If true, then the \"src/packlets\" folder exists.\n */\n public readonly projectUsesPacklets: boolean;\n\n /**\n * The absolute path of the \"src/packlets\" folder.\n */\n public readonly packletsFolderPath: string | undefined;\n\n /**\n * The packlet that the inputFilePath is under, if any.\n */\n public readonly inputFilePackletName: string | undefined;\n\n /**\n * Returns true if inputFilePath belongs to a packlet and is the entry point index.ts.\n */\n public readonly isEntryPoint: boolean;\n\n private constructor(inputFilePath: string, tsconfigFilePath: string | undefined) {\n this.inputFilePath = inputFilePath;\n this.error = undefined;\n this.nothingToDo = false;\n this.projectUsesPacklets = false;\n this.packletsFolderPath = undefined;\n this.inputFilePackletName = undefined;\n this.isEntryPoint = false;\n\n // Example: /path/to/my-project/src\n let srcFolderPath: string | undefined;\n\n if (!tsconfigFilePath) {\n this.error = { messageId: 'missing-tsconfig' };\n return;\n }\n\n srcFolderPath = Path.join(Path.dirname(tsconfigFilePath), 'src');\n\n if (!fs.existsSync(srcFolderPath)) {\n this.error = { messageId: 'missing-src-folder', data: { srcFolderPath } };\n return;\n }\n\n if (!Path.isUnder(inputFilePath, srcFolderPath)) {\n // Ignore files outside the \"src\" folder\n this.nothingToDo = true;\n return;\n }\n\n // Example: packlets/my-packlet/index.ts\n const inputFilePathRelativeToSrc: string = Path.relative(srcFolderPath, inputFilePath);\n\n // Example: [ 'packlets', 'my-packlet', 'index.ts' ]\n const pathParts: string[] = inputFilePathRelativeToSrc.split(/[\\/\\\\]+/);\n\n let underPackletsFolder: boolean = false;\n\n const expectedPackletsFolder: string = Path.join(srcFolderPath, 'packlets');\n\n for (let i = 0; i < pathParts.length; ++i) {\n const pathPart: string = pathParts[i];\n if (pathPart.toUpperCase() === 'PACKLETS') {\n if (pathPart !== 'packlets') {\n // Example: /path/to/my-project/src/PACKLETS\n const packletsFolderPath: string = Path.join(srcFolderPath, ...pathParts.slice(0, i + 1));\n this.error = { messageId: 'packlet-folder-case', data: { packletsFolderPath } };\n return;\n }\n\n if (i !== 0) {\n this.error = { messageId: 'misplaced-packlets-folder', data: { expectedPackletsFolder } };\n return;\n }\n\n underPackletsFolder = true;\n }\n }\n\n if (underPackletsFolder || fs.existsSync(expectedPackletsFolder)) {\n // packletsAbsolutePath\n this.projectUsesPacklets = true;\n this.packletsFolderPath = expectedPackletsFolder;\n }\n\n if (underPackletsFolder) {\n if (pathParts.length === 2) {\n // Example: src/packlets/SomeFile.ts\n this.error = { messageId: 'file-in-packets-folder' };\n return;\n }\n if (pathParts.length >= 2) {\n // Example: 'my-packlet'\n const packletName: string = pathParts[1];\n this.inputFilePackletName = packletName;\n\n if (pathParts.length === 3) {\n // Example: 'index.ts' or 'index.tsx'\n const thirdPart: string = pathParts[2];\n\n // Example: 'index'\n const thirdPartWithoutExtension: string = Path.parse(thirdPart).name;\n\n if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') {\n if (!PackletAnalyzer._validPackletName.test(packletName)) {\n this.error = { messageId: 'invalid-packlet-name', data: { packletName } };\n return;\n }\n\n this.isEntryPoint = true;\n }\n }\n }\n }\n\n if (this.error === undefined && !this.projectUsesPacklets) {\n this.nothingToDo = true;\n }\n }\n\n public static analyzeInputFile(inputFilePath: string, tsconfigFilePath: string | undefined) {\n return new PackletAnalyzer(inputFilePath, tsconfigFilePath);\n }\n\n public analyzeImport(modulePath: string): IAnalyzerError | undefined {\n if (!this.packletsFolderPath) {\n // The caller should ensure this can never happen\n throw new Error('Internal error: packletsFolderPath is not defined');\n }\n\n // Example: /path/to/my-project/src/packlets/my-packlet\n const inputFileFolder: string = Path.dirname(this.inputFilePath);\n\n // Example: /path/to/my-project/src/other-packlet/index\n const importedPath: string = Path.resolve(inputFileFolder, modulePath);\n\n // Is the imported path referring to a file under the src/packlets folder?\n if (Path.isUnder(importedPath, this.packletsFolderPath)) {\n // Example: other-packlet/index\n const importedPathRelativeToPackletsFolder: string = Path.relative(\n this.packletsFolderPath,\n importedPath\n );\n // Example: [ 'other-packlet', 'index' ]\n const importedPathParts: string[] = importedPathRelativeToPackletsFolder.split(/[\\/\\\\]+/);\n if (importedPathParts.length > 0) {\n // Example: 'other-packlet'\n const importedPackletName: string = importedPathParts[0];\n\n // We are importing from a packlet. Is the input file part of the same packlet?\n if (this.inputFilePackletName && importedPackletName === this.inputFilePackletName) {\n // Yes. Then our import must NOT use the packlet entry point.\n\n // Example: 'index'\n //\n // We discard the file extension to handle a degenerate case like:\n // import { X } from \"../index.js\";\n const lastPart: string = Path.parse(importedPathParts[importedPathParts.length - 1]).name;\n let pathToCompare: string;\n if (lastPart.toUpperCase() === 'INDEX') {\n // Example:\n // importedPath = /path/to/my-project/src/other-packlet/index\n // pathToCompare = /path/to/my-project/src/other-packlet\n pathToCompare = Path.dirname(importedPath);\n } else {\n pathToCompare = importedPath;\n }\n\n // Example: /path/to/my-project/src/other-packlet\n const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName);\n\n if (Path.isEqual(pathToCompare, entryPointPath)) {\n return {\n messageId: 'circular-entry-point'\n };\n }\n } else {\n // No. If we are not part of the same packlet, then the module path must refer\n // to the index.ts entry point.\n\n // Example: /path/to/my-project/src/other-packlet\n const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName);\n\n if (!Path.isEqual(importedPath, entryPointPath)) {\n // Example: \"../packlets/other-packlet\"\n const entryPointModulePath: string = Path.convertToSlashes(\n Path.relative(inputFileFolder, entryPointPath)\n );\n\n return {\n messageId: 'bypassed-entry-point',\n data: { entryPointModulePath }\n };\n }\n }\n }\n } else {\n // The imported path does NOT refer to a file under the src/packlets folder\n if (this.inputFilePackletName) {\n return {\n messageId: 'packlet-importing-project-file'\n };\n }\n }\n\n return undefined;\n }\n}\n"]}
package/lib/Path.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Path.js","sourceRoot":"","sources":["../src/Path.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport * as path from 'path';\r\nimport * as fs from 'fs';\r\n\r\nexport type ParsedPath = path.ParsedPath;\r\n\r\nexport class Path {\r\n /**\r\n * Whether the filesystem is assumed to be case sensitive for Path operations.\r\n *\r\n * @remarks\r\n * Regardless of operating system, a given file system's paths may be case-sensitive or case-insensitive.\r\n * If a volume is mounted under a subfolder, then different parts of a path can even have different\r\n * case-sensitivity. The Node.js \"path\" API naively assumes that all Windows paths are case-insensitive,\r\n * and that all other OS's are case-sensitive. This is way off, for example a modern MacBook has a\r\n * case-insensitive filesystem by default. There isn't an easy workaround because Node.js does not expose\r\n * the native OS APIs that would give accurate answers.\r\n *\r\n * The TypeScript compiler does somewhat better: it performs an empirical test of its own bundle path to see\r\n * whether it can be read using different case. If so, it normalizes all paths to lowercase (sometimes with\r\n * no API for retrieving the real path). This caused our Path.isUnder() to return incorrect answers because\r\n * it relies on Node.js path.relative().\r\n *\r\n * To solve that problem, Path.ts performs an empirical test similar to what the TypeScript compiler does,\r\n * and then we adjust path.relative() to be case insensitive if appropriate.\r\n *\r\n * @see {@link https://nodejs.org/en/docs/guides/working-with-different-filesystems/}\r\n */\r\n public static usingCaseSensitive: boolean = Path._detectCaseSensitive();\r\n\r\n private static _detectCaseSensitive(): boolean {\r\n // Can our own file be accessed using a path with different case? If so, then the filesystem is case-insensitive.\r\n return !fs.existsSync(__filename.toUpperCase());\r\n }\r\n\r\n // Removes redundant trailing slashes from a path.\r\n private static _trimTrailingSlashes(inputPath: string): string {\r\n // Examples:\r\n // \"/a/b///\\\\\" --> \"/a/b\"\r\n // \"/\" --> \"/\"\r\n return inputPath.replace(/(?<=[^\\/\\\\])[\\/\\\\]+$/, '');\r\n }\r\n\r\n // An implementation of path.relative() that is case-insensitive.\r\n private static _relativeCaseInsensitive(from: string, to: string): string {\r\n // path.relative() apples path.normalize() and also trims any trailing slashes.\r\n // Since we'll be matching toNormalized against result, we need to do that for our string as well.\r\n const normalizedTo: string = Path._trimTrailingSlashes(path.normalize(to));\r\n\r\n // We start by converting everything to uppercase and call path.relative()\r\n const uppercasedFrom: string = from.toUpperCase();\r\n const uppercasedTo: string = normalizedTo.toUpperCase();\r\n\r\n // The result will be all uppercase because its inputs were uppercased\r\n const uppercasedResult: string = path.relative(uppercasedFrom, uppercasedTo);\r\n\r\n // Are there any cased characters in the result?\r\n if (uppercasedResult.toLowerCase() === uppercasedResult) {\r\n // No cased characters\r\n // Example: \"../..\"\r\n return uppercasedResult;\r\n }\r\n\r\n // Example:\r\n // from=\"/a/b/c\"\r\n // to=\"/a/b/d/e\"\r\n //\r\n // fromNormalized=\"/A/B/C\"\r\n // toNormalized=\"/A/B/D/E\"\r\n //\r\n // result=\"../D/E\"\r\n //\r\n // Scan backwards comparing uppercasedResult versus uppercasedTo, stopping at the first place where they differ.\r\n let resultIndex: number = uppercasedResult.length;\r\n let toIndex: number = normalizedTo.length;\r\n for (;;) {\r\n if (resultIndex === 0 || toIndex === 0) {\r\n // Stop if we reach the start of the string\r\n break;\r\n }\r\n\r\n if (uppercasedResult.charCodeAt(resultIndex - 1) !== uppercasedTo.charCodeAt(toIndex - 1)) {\r\n // Stop before we reach a character that is different\r\n break;\r\n }\r\n\r\n --resultIndex;\r\n --toIndex;\r\n }\r\n\r\n // Replace the matching part with the properly cased substring from the \"normalizedTo\" input\r\n //\r\n // Example:\r\n // \"..\" + \"/d/e\" = \"../d/e\"\r\n return uppercasedResult.substring(0, resultIndex) + normalizedTo.substring(toIndex);\r\n }\r\n\r\n public static relative(from: string, to: string): string {\r\n if (!Path.usingCaseSensitive) {\r\n return Path._relativeCaseInsensitive(from, to);\r\n }\r\n return path.relative(from, to);\r\n }\r\n\r\n // --------------------------------------------------------------------------------------------------------\r\n // The operations below don't care about case sensitivity\r\n\r\n public static dirname(p: string): string {\r\n return path.dirname(p);\r\n }\r\n\r\n public static join(...paths: string[]): string {\r\n return path.join(...paths);\r\n }\r\n\r\n public static resolve(...pathSegments: string[]): string {\r\n return path.resolve(...pathSegments);\r\n }\r\n\r\n public static parse(pathString: string): ParsedPath {\r\n return path.parse(pathString);\r\n }\r\n\r\n // --------------------------------------------------------------------------------------------------------\r\n // The operations below are borrowed from @rushstack/node-core-library\r\n\r\n private static _relativePathRegex: RegExp = /^[.\\/\\\\]+$/;\r\n\r\n /**\r\n * Returns true if \"childPath\" is located inside the \"parentFolderPath\" folder\r\n * or one of its child folders. Note that \"parentFolderPath\" is not considered to be\r\n * under itself. The \"childPath\" can refer to any type of file system object.\r\n *\r\n * @remarks\r\n * The indicated file/folder objects are not required to actually exist on disk.\r\n * For example, \"parentFolderPath\" is interpreted as a folder name even if it refers to a file.\r\n * If the paths are relative, they will first be resolved using path.resolve().\r\n */\r\n public static isUnder(childPath: string, parentFolderPath: string): boolean {\r\n const relativePath: string = Path.relative(childPath, parentFolderPath);\r\n return Path._relativePathRegex.test(relativePath);\r\n }\r\n\r\n /**\r\n * Returns true if `path1` and `path2` refer to the same underlying path.\r\n *\r\n * @remarks\r\n *\r\n * The comparison is performed using `path.relative()`.\r\n */\r\n public static isEqual(path1: string, path2: string): boolean {\r\n return Path.relative(path1, path2) === '';\r\n }\r\n\r\n /**\r\n * Replaces Windows-style backslashes with POSIX-style slashes.\r\n *\r\n * @remarks\r\n * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc.\r\n */\r\n public static convertToSlashes(inputPath: string): string {\r\n return inputPath.split('\\\\').join('/');\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"Path.js","sourceRoot":"","sources":["../src/Path.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nexport type ParsedPath = path.ParsedPath;\n\nexport class Path {\n /**\n * Whether the filesystem is assumed to be case sensitive for Path operations.\n *\n * @remarks\n * Regardless of operating system, a given file system's paths may be case-sensitive or case-insensitive.\n * If a volume is mounted under a subfolder, then different parts of a path can even have different\n * case-sensitivity. The Node.js \"path\" API naively assumes that all Windows paths are case-insensitive,\n * and that all other OS's are case-sensitive. This is way off, for example a modern MacBook has a\n * case-insensitive filesystem by default. There isn't an easy workaround because Node.js does not expose\n * the native OS APIs that would give accurate answers.\n *\n * The TypeScript compiler does somewhat better: it performs an empirical test of its own bundle path to see\n * whether it can be read using different case. If so, it normalizes all paths to lowercase (sometimes with\n * no API for retrieving the real path). This caused our Path.isUnder() to return incorrect answers because\n * it relies on Node.js path.relative().\n *\n * To solve that problem, Path.ts performs an empirical test similar to what the TypeScript compiler does,\n * and then we adjust path.relative() to be case insensitive if appropriate.\n *\n * @see {@link https://nodejs.org/en/docs/guides/working-with-different-filesystems/}\n */\n public static usingCaseSensitive: boolean = Path._detectCaseSensitive();\n\n private static _detectCaseSensitive(): boolean {\n // Can our own file be accessed using a path with different case? If so, then the filesystem is case-insensitive.\n return !fs.existsSync(__filename.toUpperCase());\n }\n\n // Removes redundant trailing slashes from a path.\n private static _trimTrailingSlashes(inputPath: string): string {\n // Examples:\n // \"/a/b///\\\\\" --> \"/a/b\"\n // \"/\" --> \"/\"\n return inputPath.replace(/(?<=[^\\/\\\\])[\\/\\\\]+$/, '');\n }\n\n // An implementation of path.relative() that is case-insensitive.\n private static _relativeCaseInsensitive(from: string, to: string): string {\n // path.relative() apples path.normalize() and also trims any trailing slashes.\n // Since we'll be matching toNormalized against result, we need to do that for our string as well.\n const normalizedTo: string = Path._trimTrailingSlashes(path.normalize(to));\n\n // We start by converting everything to uppercase and call path.relative()\n const uppercasedFrom: string = from.toUpperCase();\n const uppercasedTo: string = normalizedTo.toUpperCase();\n\n // The result will be all uppercase because its inputs were uppercased\n const uppercasedResult: string = path.relative(uppercasedFrom, uppercasedTo);\n\n // Are there any cased characters in the result?\n if (uppercasedResult.toLowerCase() === uppercasedResult) {\n // No cased characters\n // Example: \"../..\"\n return uppercasedResult;\n }\n\n // Example:\n // from=\"/a/b/c\"\n // to=\"/a/b/d/e\"\n //\n // fromNormalized=\"/A/B/C\"\n // toNormalized=\"/A/B/D/E\"\n //\n // result=\"../D/E\"\n //\n // Scan backwards comparing uppercasedResult versus uppercasedTo, stopping at the first place where they differ.\n let resultIndex: number = uppercasedResult.length;\n let toIndex: number = normalizedTo.length;\n for (;;) {\n if (resultIndex === 0 || toIndex === 0) {\n // Stop if we reach the start of the string\n break;\n }\n\n if (uppercasedResult.charCodeAt(resultIndex - 1) !== uppercasedTo.charCodeAt(toIndex - 1)) {\n // Stop before we reach a character that is different\n break;\n }\n\n --resultIndex;\n --toIndex;\n }\n\n // Replace the matching part with the properly cased substring from the \"normalizedTo\" input\n //\n // Example:\n // \"..\" + \"/d/e\" = \"../d/e\"\n return uppercasedResult.substring(0, resultIndex) + normalizedTo.substring(toIndex);\n }\n\n public static relative(from: string, to: string): string {\n if (!Path.usingCaseSensitive) {\n return Path._relativeCaseInsensitive(from, to);\n }\n return path.relative(from, to);\n }\n\n // --------------------------------------------------------------------------------------------------------\n // The operations below don't care about case sensitivity\n\n public static dirname(p: string): string {\n return path.dirname(p);\n }\n\n public static join(...paths: string[]): string {\n return path.join(...paths);\n }\n\n public static resolve(...pathSegments: string[]): string {\n return path.resolve(...pathSegments);\n }\n\n public static parse(pathString: string): ParsedPath {\n return path.parse(pathString);\n }\n\n // --------------------------------------------------------------------------------------------------------\n // The operations below are borrowed from @rushstack/node-core-library\n\n private static _relativePathRegex: RegExp = /^[.\\/\\\\]+$/;\n\n /**\n * Returns true if \"childPath\" is located inside the \"parentFolderPath\" folder\n * or one of its child folders. Note that \"parentFolderPath\" is not considered to be\n * under itself. The \"childPath\" can refer to any type of file system object.\n *\n * @remarks\n * The indicated file/folder objects are not required to actually exist on disk.\n * For example, \"parentFolderPath\" is interpreted as a folder name even if it refers to a file.\n * If the paths are relative, they will first be resolved using path.resolve().\n */\n public static isUnder(childPath: string, parentFolderPath: string): boolean {\n const relativePath: string = Path.relative(childPath, parentFolderPath);\n return Path._relativePathRegex.test(relativePath);\n }\n\n /**\n * Returns true if `path1` and `path2` refer to the same underlying path.\n *\n * @remarks\n *\n * The comparison is performed using `path.relative()`.\n */\n public static isEqual(path1: string, path2: string): boolean {\n return Path.relative(path1, path2) === '';\n }\n\n /**\n * Replaces Windows-style backslashes with POSIX-style slashes.\n *\n * @remarks\n * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc.\n */\n public static convertToSlashes(inputPath: string): string {\n return inputPath.split('\\\\').join('/');\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"circular-deps.js","sourceRoot":"","sources":["../src/circular-deps.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAM3D,8EAAoE;AAEpE,uDAAoD;AACpD,6DAA0E;AAC1E,iCAA8B;AAK9B,MAAM,YAAY,GAA6C;IAC7D,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,EAAE,iBAAiB,EAAE,0DAA0D,EAAE;QAC3F,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,IAAI,EAAE;YACJ,WAAW,EAAE,kDAAkD;YAC/D,4DAA4D;YAC5D,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,MAAM;YACnB,GAAG,EAAE,iEAAiE;SAC1C;KAC/B;IAED,MAAM,EAAE,CAAC,OAAkD,EAAE,EAAE;QAC7D,gEAAgE;QAChE,MAAM,aAAa,GAAW,OAAO,CAAC,WAAW,EAAE,CAAC;QAEpD,6CAA6C;QAC7C,MAAM,OAAO,GAAe,gCAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QAC3E,MAAM,gBAAgB,GAAuB,OAAO,CAAC,kBAAkB,EAAE,CAAC,gBAAgB,CAAW,CAAC;QAEtG,MAAM,eAAe,GAAoB,iCAAe,CAAC,gBAAgB,CACvE,aAAa,EACb,gBAAgB,CACjB,CAAC;QACF,IAAI,eAAe,CAAC,WAAW,EAAE;YAC/B,OAAO,EAAE,CAAC;SACX;QAED,OAAO;YACL,mGAAmG;YACnG,yGAAyG;YACzG,gDAAgD;YAChD,OAAO,EAAE,CAAC,IAAmB,EAAQ,EAAE;gBACrC,IAAI,eAAe,CAAC,YAAY,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;oBAC1D,MAAM,cAAc,GAClB,uCAAkB,CAAC,gCAAgC,CACjD,eAAe,CAAC,oBAAqB,EACrC,eAAe,EACf,OAAO,CACR,CAAC;oBAEJ,IAAI,cAAc,EAAE;wBAClB,MAAM,kBAAkB,GAAW,WAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;wBAElE,MAAM,oBAAoB,GAAa,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;wBAEhF,wGAAwG;wBACxG,4EAA4E;wBAC5E,oBAAoB,CAAC,IAAI,EAAE,CAAC;wBAC5B,IAAI,oBAAoB,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,oBAAoB,EAAE;4BACpE,IAAI,MAAM,GAAW,EAAE,CAAC;4BACxB,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE;gCAC1C,MAAM,QAAQ,GAAW,WAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;gCACvF,MAAM,IAAI,IAAI,aAAa,CAAC,WAAW,sBAAsB,QAAQ,IAAI,CAAC;6BAC3E;4BAED,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,IAAI;gCACV,SAAS,EAAE,iBAAiB;gCAC5B,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;6BACzB,CAAC,CAAC;yBACJ;qBACF;iBACF;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEO,oCAAY","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport type * as ts from 'typescript';\r\nimport * as path from 'path';\r\n\r\nimport type { ParserServices, TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\r\nimport { ESLintUtils } from '@typescript-eslint/experimental-utils';\r\n\r\nimport { PackletAnalyzer } from './PackletAnalyzer';\r\nimport { DependencyAnalyzer, IPackletImport } from './DependencyAnalyzer';\r\nimport { Path } from './Path';\r\n\r\nexport type MessageIds = 'circular-import';\r\ntype Options = [];\r\n\r\nconst circularDeps: TSESLint.RuleModule<MessageIds, Options> = {\r\n meta: {\r\n type: 'problem',\r\n messages: { 'circular-import': 'Packlet imports create a circular reference:\\n{{report}}' },\r\n schema: [\r\n {\r\n type: 'object',\r\n additionalProperties: false\r\n }\r\n ],\r\n docs: {\r\n description: 'Check for circular dependencies between packlets',\r\n // Deprecated in ESLint v8; Keep for backwards compatibility\r\n category: 'Best Practices',\r\n recommended: 'warn',\r\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\r\n } as TSESLint.RuleMetaDataDocs\r\n },\r\n\r\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\r\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\r\n const inputFilePath: string = context.getFilename();\r\n\r\n // Example: /path/to/my-project/tsconfig.json\r\n const program: ts.Program = ESLintUtils.getParserServices(context).program;\r\n const tsconfigFilePath: string | undefined = program.getCompilerOptions()['configFilePath'] as string;\r\n\r\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\r\n inputFilePath,\r\n tsconfigFilePath\r\n );\r\n if (packletAnalyzer.nothingToDo) {\r\n return {};\r\n }\r\n\r\n return {\r\n // Match the first node in the source file. Ideally we should be matching \"Program > :first-child\"\r\n // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector:\r\n // https://github.com/estools/esquery/issues/114\r\n Program: (node: TSESTree.Node): void => {\r\n if (packletAnalyzer.isEntryPoint && !packletAnalyzer.error) {\r\n const packletImports: IPackletImport[] | undefined =\r\n DependencyAnalyzer.checkEntryPointForCircularImport(\r\n packletAnalyzer.inputFilePackletName!,\r\n packletAnalyzer,\r\n program\r\n );\r\n\r\n if (packletImports) {\r\n const tsconfigFileFolder: string = Path.dirname(tsconfigFilePath);\r\n\r\n const affectedPackletNames: string[] = packletImports.map((x) => x.packletName);\r\n\r\n // If 3 different packlets form a circular dependency, we don't need to report the same warning 3 times.\r\n // Instead, only report the warning for the alphabetically smallest packlet.\r\n affectedPackletNames.sort();\r\n if (affectedPackletNames[0] === packletAnalyzer.inputFilePackletName) {\r\n let report: string = '';\r\n for (const packletImport of packletImports) {\r\n const filePath: string = Path.relative(tsconfigFileFolder, packletImport.fromFilePath);\r\n report += `\"${packletImport.packletName}\" is referenced by ${filePath}\\n`;\r\n }\r\n\r\n context.report({\r\n node: node,\r\n messageId: 'circular-import',\r\n data: { report: report }\r\n });\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n};\r\n\r\nexport { circularDeps };\r\n"]}
1
+ {"version":3,"file":"circular-deps.js","sourceRoot":"","sources":["../src/circular-deps.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAM3D,8EAAoE;AAEpE,uDAAoD;AACpD,6DAA0E;AAC1E,iCAA8B;AAK9B,MAAM,YAAY,GAA6C;IAC7D,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,EAAE,iBAAiB,EAAE,0DAA0D,EAAE;QAC3F,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,IAAI,EAAE;YACJ,WAAW,EAAE,kDAAkD;YAC/D,4DAA4D;YAC5D,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,MAAM;YACnB,GAAG,EAAE,iEAAiE;SAC1C;KAC/B;IAED,MAAM,EAAE,CAAC,OAAkD,EAAE,EAAE;QAC7D,gEAAgE;QAChE,MAAM,aAAa,GAAW,OAAO,CAAC,WAAW,EAAE,CAAC;QAEpD,6CAA6C;QAC7C,MAAM,OAAO,GAAe,gCAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QAC3E,MAAM,gBAAgB,GAAuB,OAAO,CAAC,kBAAkB,EAAE,CAAC,gBAAgB,CAAW,CAAC;QAEtG,MAAM,eAAe,GAAoB,iCAAe,CAAC,gBAAgB,CACvE,aAAa,EACb,gBAAgB,CACjB,CAAC;QACF,IAAI,eAAe,CAAC,WAAW,EAAE;YAC/B,OAAO,EAAE,CAAC;SACX;QAED,OAAO;YACL,mGAAmG;YACnG,yGAAyG;YACzG,gDAAgD;YAChD,OAAO,EAAE,CAAC,IAAmB,EAAQ,EAAE;gBACrC,IAAI,eAAe,CAAC,YAAY,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;oBAC1D,MAAM,cAAc,GAClB,uCAAkB,CAAC,gCAAgC,CACjD,eAAe,CAAC,oBAAqB,EACrC,eAAe,EACf,OAAO,CACR,CAAC;oBAEJ,IAAI,cAAc,EAAE;wBAClB,MAAM,kBAAkB,GAAW,WAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;wBAElE,MAAM,oBAAoB,GAAa,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;wBAEhF,wGAAwG;wBACxG,4EAA4E;wBAC5E,oBAAoB,CAAC,IAAI,EAAE,CAAC;wBAC5B,IAAI,oBAAoB,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,oBAAoB,EAAE;4BACpE,IAAI,MAAM,GAAW,EAAE,CAAC;4BACxB,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE;gCAC1C,MAAM,QAAQ,GAAW,WAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;gCACvF,MAAM,IAAI,IAAI,aAAa,CAAC,WAAW,sBAAsB,QAAQ,IAAI,CAAC;6BAC3E;4BAED,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,IAAI;gCACV,SAAS,EAAE,iBAAiB;gCAC5B,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;6BACzB,CAAC,CAAC;yBACJ;qBACF;iBACF;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEO,oCAAY","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as ts from 'typescript';\nimport * as path from 'path';\n\nimport type { ParserServices, TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\nimport { ESLintUtils } from '@typescript-eslint/experimental-utils';\n\nimport { PackletAnalyzer } from './PackletAnalyzer';\nimport { DependencyAnalyzer, IPackletImport } from './DependencyAnalyzer';\nimport { Path } from './Path';\n\nexport type MessageIds = 'circular-import';\ntype Options = [];\n\nconst circularDeps: TSESLint.RuleModule<MessageIds, Options> = {\n meta: {\n type: 'problem',\n messages: { 'circular-import': 'Packlet imports create a circular reference:\\n{{report}}' },\n schema: [\n {\n type: 'object',\n additionalProperties: false\n }\n ],\n docs: {\n description: 'Check for circular dependencies between packlets',\n // Deprecated in ESLint v8; Keep for backwards compatibility\n category: 'Best Practices',\n recommended: 'warn',\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\n } as TSESLint.RuleMetaDataDocs\n },\n\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\n const inputFilePath: string = context.getFilename();\n\n // Example: /path/to/my-project/tsconfig.json\n const program: ts.Program = ESLintUtils.getParserServices(context).program;\n const tsconfigFilePath: string | undefined = program.getCompilerOptions()['configFilePath'] as string;\n\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\n inputFilePath,\n tsconfigFilePath\n );\n if (packletAnalyzer.nothingToDo) {\n return {};\n }\n\n return {\n // Match the first node in the source file. Ideally we should be matching \"Program > :first-child\"\n // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector:\n // https://github.com/estools/esquery/issues/114\n Program: (node: TSESTree.Node): void => {\n if (packletAnalyzer.isEntryPoint && !packletAnalyzer.error) {\n const packletImports: IPackletImport[] | undefined =\n DependencyAnalyzer.checkEntryPointForCircularImport(\n packletAnalyzer.inputFilePackletName!,\n packletAnalyzer,\n program\n );\n\n if (packletImports) {\n const tsconfigFileFolder: string = Path.dirname(tsconfigFilePath);\n\n const affectedPackletNames: string[] = packletImports.map((x) => x.packletName);\n\n // If 3 different packlets form a circular dependency, we don't need to report the same warning 3 times.\n // Instead, only report the warning for the alphabetically smallest packlet.\n affectedPackletNames.sort();\n if (affectedPackletNames[0] === packletAnalyzer.inputFilePackletName) {\n let report: string = '';\n for (const packletImport of packletImports) {\n const filePath: string = Path.relative(tsconfigFileFolder, packletImport.fromFilePath);\n report += `\"${packletImport.packletName}\" is referenced by ${filePath}\\n`;\n }\n\n context.report({\n node: node,\n messageId: 'circular-import',\n data: { report: report }\n });\n }\n }\n }\n }\n };\n }\n};\n\nexport { circularDeps };\n"]}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;AAG3D,2CAAwC;AACxC,mDAA+C;AAC/C,qCAAkC;AAOlC,MAAM,MAAM,GAAY;IACtB,KAAK,EAAE;QACL,6CAA6C;QAC7C,SAAS,EAAE,qBAAS;QACpB,iDAAiD;QACjD,eAAe,EAAE,4BAAY;QAC7B,MAAM,EAAE,eAAM;KACf;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,mCAAmC,CAAC;YAC9C,KAAK,EAAE;gBACL,+BAA+B,EAAE,MAAM;gBACvC,mCAAmC,EAAE,MAAM;gBAC3C,4BAA4B,EAAE,KAAK;aACpC;SACF;KACF;CACF,CAAC;AAEF,iBAAS,MAAM,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport { TSESLint } from '@typescript-eslint/experimental-utils';\r\nimport { mechanics } from './mechanics';\r\nimport { circularDeps } from './circular-deps';\r\nimport { readme } from './readme';\r\n\r\ninterface IPlugin {\r\n rules: { [ruleName: string]: TSESLint.RuleModule<string, unknown[]> };\r\n configs: { [ruleName: string]: any };\r\n}\r\n\r\nconst plugin: IPlugin = {\r\n rules: {\r\n // Full name: \"@rushstack/packlets/mechanics\"\r\n mechanics: mechanics,\r\n // Full name: \"@rushstack/packlets/circular-deps\"\r\n 'circular-deps': circularDeps,\r\n readme: readme\r\n },\r\n configs: {\r\n recommended: {\r\n plugins: ['@rushstack/eslint-plugin-packlets'],\r\n rules: {\r\n '@rushstack/packlets/mechanics': 'warn',\r\n '@rushstack/packlets/circular-deps': 'warn',\r\n '@rushstack/packlets/readme': 'off'\r\n }\r\n }\r\n }\r\n};\r\n\r\nexport = plugin;\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;AAG3D,2CAAwC;AACxC,mDAA+C;AAC/C,qCAAkC;AAOlC,MAAM,MAAM,GAAY;IACtB,KAAK,EAAE;QACL,6CAA6C;QAC7C,SAAS,EAAE,qBAAS;QACpB,iDAAiD;QACjD,eAAe,EAAE,4BAAY;QAC7B,MAAM,EAAE,eAAM;KACf;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,mCAAmC,CAAC;YAC9C,KAAK,EAAE;gBACL,+BAA+B,EAAE,MAAM;gBACvC,mCAAmC,EAAE,MAAM;gBAC3C,4BAA4B,EAAE,KAAK;aACpC;SACF;KACF;CACF,CAAC;AAEF,iBAAS,MAAM,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { TSESLint } from '@typescript-eslint/experimental-utils';\nimport { mechanics } from './mechanics';\nimport { circularDeps } from './circular-deps';\nimport { readme } from './readme';\n\ninterface IPlugin {\n rules: { [ruleName: string]: TSESLint.RuleModule<string, unknown[]> };\n configs: { [ruleName: string]: any };\n}\n\nconst plugin: IPlugin = {\n rules: {\n // Full name: \"@rushstack/packlets/mechanics\"\n mechanics: mechanics,\n // Full name: \"@rushstack/packlets/circular-deps\"\n 'circular-deps': circularDeps,\n readme: readme\n },\n configs: {\n recommended: {\n plugins: ['@rushstack/eslint-plugin-packlets'],\n rules: {\n '@rushstack/packlets/mechanics': 'warn',\n '@rushstack/packlets/circular-deps': 'warn',\n '@rushstack/packlets/readme': 'off'\n }\n }\n }\n};\n\nexport = plugin;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mechanics.js","sourceRoot":"","sources":["../src/mechanics.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport type { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\r\nimport { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/experimental-utils';\r\n\r\nimport { PackletAnalyzer, IAnalyzerError, InputFileMessageIds, ImportMessageIds } from './PackletAnalyzer';\r\n\r\nexport type MessageIds = InputFileMessageIds | ImportMessageIds;\r\ntype Options = [];\r\n\r\nconst mechanics: TSESLint.RuleModule<MessageIds, Options> = {\r\n meta: {\r\n type: 'problem',\r\n messages: {\r\n // InputFileMessageIds\r\n 'file-in-packets-folder': 'The \"packlets\" folder must not contain regular source files',\r\n 'invalid-packlet-name':\r\n 'Invalid packlet name \"{{packletName}}\".' +\r\n ' The name must be lowercase alphanumeric words separated by hyphens. Example: \"my-packlet\"',\r\n 'misplaced-packlets-folder': 'The packlets folder must be located at \"{{expectedPackletsFolder}}\"',\r\n 'missing-src-folder': 'Expecting to find a \"src\" folder at: {{srcFolderPath}}',\r\n 'missing-tsconfig':\r\n 'In order to use @rushstack/eslint-plugin-packlets, your ESLint config file' +\r\n ' must configure the TypeScript parser',\r\n 'packlet-folder-case': 'The packlets folder must be all lower case: {{packletsFolderPath}}',\r\n\r\n // ImportMessageIds\r\n 'bypassed-entry-point':\r\n 'The import statement does not use the packlet\\'s entry point \"{{entryPointModulePath}}\"',\r\n 'circular-entry-point': 'Files under a packlet folder must not import from their own index.ts file',\r\n 'packlet-importing-project-file':\r\n 'A local project file cannot be imported.' +\r\n \" A packlet's dependencies must be NPM packages and/or other packlets.\"\r\n },\r\n schema: [\r\n {\r\n type: 'object',\r\n additionalProperties: false\r\n }\r\n ],\r\n docs: {\r\n description: 'Check that file paths and imports follow the basic mechanics for the packlet formalism',\r\n // Deprecated in ESLint v8; Keep for backwards compatibility\r\n category: 'Best Practices',\r\n recommended: 'warn',\r\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\r\n } as TSESLint.RuleMetaDataDocs\r\n },\r\n\r\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\r\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\r\n const inputFilePath: string = context.getFilename();\r\n\r\n // Example: /path/to/my-project/tsconfig.json\r\n const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices(\r\n context\r\n ).program.getCompilerOptions()['configFilePath'] as string;\r\n\r\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\r\n inputFilePath,\r\n tsconfigFilePath\r\n );\r\n if (packletAnalyzer.nothingToDo) {\r\n return {};\r\n }\r\n\r\n return {\r\n // Match the first node in the source file. Ideally we should be matching \"Program > :first-child\"\r\n // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector:\r\n // https://github.com/estools/esquery/issues/114\r\n Program: (node: TSESTree.Node): void => {\r\n if (packletAnalyzer.error) {\r\n context.report({\r\n node: node,\r\n messageId: packletAnalyzer.error.messageId,\r\n data: packletAnalyzer.error.data\r\n });\r\n }\r\n },\r\n\r\n // ImportDeclaration matches these forms:\r\n // import { X } from '../../packlets/other-packlet';\r\n // import X from '../../packlets/other-packlet';\r\n // import type { X, Y } from '../../packlets/other-packlet';\r\n // import * as X from '../../packlets/other-packlet';\r\n //\r\n // ExportNamedDeclaration matches these forms:\r\n // export { X } from '../../packlets/other-packlet';\r\n //\r\n // ExportAllDeclaration matches these forms:\r\n // export * from '../../packlets/other-packlet';\r\n // export * as X from '../../packlets/other-packlet';\r\n 'ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration': (\r\n node: TSESTree.ImportDeclaration | TSESTree.ExportNamedDeclaration | TSESTree.ExportAllDeclaration\r\n ): void => {\r\n if (node.source?.type === AST_NODE_TYPES.Literal) {\r\n if (packletAnalyzer.projectUsesPacklets) {\r\n // Extract the import/export module path\r\n // Example: \"../../packlets/other-packlet\"\r\n const modulePath = node.source.value;\r\n if (typeof modulePath !== 'string') {\r\n return;\r\n }\r\n\r\n if (!(modulePath.startsWith('.') || modulePath.startsWith('..'))) {\r\n // It's not a local import.\r\n\r\n // Examples:\r\n // import { X } from \"npm-package\";\r\n // import { X } from \"raw-loader!./webpack-file.ts\";\r\n return;\r\n }\r\n\r\n const lint: IAnalyzerError | undefined = packletAnalyzer.analyzeImport(modulePath);\r\n if (lint) {\r\n context.report({\r\n node: node,\r\n messageId: lint.messageId,\r\n data: lint.data\r\n });\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n};\r\n\r\nexport { mechanics };\r\n"]}
1
+ {"version":3,"file":"mechanics.js","sourceRoot":"","sources":["../src/mechanics.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\nimport { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/experimental-utils';\n\nimport { PackletAnalyzer, IAnalyzerError, InputFileMessageIds, ImportMessageIds } from './PackletAnalyzer';\n\nexport type MessageIds = InputFileMessageIds | ImportMessageIds;\ntype Options = [];\n\nconst mechanics: TSESLint.RuleModule<MessageIds, Options> = {\n meta: {\n type: 'problem',\n messages: {\n // InputFileMessageIds\n 'file-in-packets-folder': 'The \"packlets\" folder must not contain regular source files',\n 'invalid-packlet-name':\n 'Invalid packlet name \"{{packletName}}\".' +\n ' The name must be lowercase alphanumeric words separated by hyphens. Example: \"my-packlet\"',\n 'misplaced-packlets-folder': 'The packlets folder must be located at \"{{expectedPackletsFolder}}\"',\n 'missing-src-folder': 'Expecting to find a \"src\" folder at: {{srcFolderPath}}',\n 'missing-tsconfig':\n 'In order to use @rushstack/eslint-plugin-packlets, your ESLint config file' +\n ' must configure the TypeScript parser',\n 'packlet-folder-case': 'The packlets folder must be all lower case: {{packletsFolderPath}}',\n\n // ImportMessageIds\n 'bypassed-entry-point':\n 'The import statement does not use the packlet\\'s entry point \"{{entryPointModulePath}}\"',\n 'circular-entry-point': 'Files under a packlet folder must not import from their own index.ts file',\n 'packlet-importing-project-file':\n 'A local project file cannot be imported.' +\n \" A packlet's dependencies must be NPM packages and/or other packlets.\"\n },\n schema: [\n {\n type: 'object',\n additionalProperties: false\n }\n ],\n docs: {\n description: 'Check that file paths and imports follow the basic mechanics for the packlet formalism',\n // Deprecated in ESLint v8; Keep for backwards compatibility\n category: 'Best Practices',\n recommended: 'warn',\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\n } as TSESLint.RuleMetaDataDocs\n },\n\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\n const inputFilePath: string = context.getFilename();\n\n // Example: /path/to/my-project/tsconfig.json\n const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices(\n context\n ).program.getCompilerOptions()['configFilePath'] as string;\n\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\n inputFilePath,\n tsconfigFilePath\n );\n if (packletAnalyzer.nothingToDo) {\n return {};\n }\n\n return {\n // Match the first node in the source file. Ideally we should be matching \"Program > :first-child\"\n // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector:\n // https://github.com/estools/esquery/issues/114\n Program: (node: TSESTree.Node): void => {\n if (packletAnalyzer.error) {\n context.report({\n node: node,\n messageId: packletAnalyzer.error.messageId,\n data: packletAnalyzer.error.data\n });\n }\n },\n\n // ImportDeclaration matches these forms:\n // import { X } from '../../packlets/other-packlet';\n // import X from '../../packlets/other-packlet';\n // import type { X, Y } from '../../packlets/other-packlet';\n // import * as X from '../../packlets/other-packlet';\n //\n // ExportNamedDeclaration matches these forms:\n // export { X } from '../../packlets/other-packlet';\n //\n // ExportAllDeclaration matches these forms:\n // export * from '../../packlets/other-packlet';\n // export * as X from '../../packlets/other-packlet';\n 'ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration': (\n node: TSESTree.ImportDeclaration | TSESTree.ExportNamedDeclaration | TSESTree.ExportAllDeclaration\n ): void => {\n if (node.source?.type === AST_NODE_TYPES.Literal) {\n if (packletAnalyzer.projectUsesPacklets) {\n // Extract the import/export module path\n // Example: \"../../packlets/other-packlet\"\n const modulePath = node.source.value;\n if (typeof modulePath !== 'string') {\n return;\n }\n\n if (!(modulePath.startsWith('.') || modulePath.startsWith('..'))) {\n // It's not a local import.\n\n // Examples:\n // import { X } from \"npm-package\";\n // import { X } from \"raw-loader!./webpack-file.ts\";\n return;\n }\n\n const lint: IAnalyzerError | undefined = packletAnalyzer.analyzeImport(modulePath);\n if (lint) {\n context.report({\n node: node,\n messageId: lint.messageId,\n data: lint.data\n });\n }\n }\n }\n }\n };\n }\n};\n\nexport { mechanics };\n"]}
package/lib/readme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"readme.js","sourceRoot":"","sources":["../src/readme.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport * as path from 'path';\r\nimport * as fs from 'fs';\r\nimport type { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\r\nimport { ESLintUtils } from '@typescript-eslint/experimental-utils';\r\n\r\nimport { PackletAnalyzer } from './PackletAnalyzer';\r\n\r\nexport type MessageIds = 'missing-readme' | 'error-reading-file' | 'readme-too-short';\r\ntype Options = [\r\n {\r\n minimumReadmeWords?: number;\r\n }\r\n];\r\n\r\nconst readme: TSESLint.RuleModule<MessageIds, Options> = {\r\n meta: {\r\n type: 'problem',\r\n messages: {\r\n 'missing-readme':\r\n 'The ESLint configuration requires each packlet to provide a README.md file summarizing' +\r\n ' its purpose and usage: {{readmePath}}',\r\n 'readme-too-short':\r\n 'The ESLint configuration requires at least {{minimumReadmeWords}} words of documentation in the' +\r\n ' README.md file: {{readmePath}}',\r\n 'error-reading-file': 'Error reading input file {{readmePath}}:\\n{{errorMessage}}'\r\n },\r\n schema: [\r\n {\r\n type: 'object',\r\n properties: {\r\n minimumReadmeWords: {\r\n type: 'number'\r\n }\r\n },\r\n additionalProperties: false\r\n }\r\n ],\r\n\r\n docs: {\r\n description: 'Require each packlet folder to have a README.md file summarizing its purpose and usage',\r\n // Deprecated in ESLint v8; Keep for backwards compatibility\r\n category: 'Best Practices',\r\n // Too strict to be recommended in the default configuration\r\n recommended: false,\r\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\r\n } as TSESLint.RuleMetaDataDocs\r\n },\r\n\r\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\r\n const minimumReadmeWords: number = context.options[0]?.minimumReadmeWords || 10;\r\n\r\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\r\n const inputFilePath: string = context.getFilename();\r\n\r\n // Example: /path/to/my-project/tsconfig.json\r\n const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices(\r\n context\r\n ).program.getCompilerOptions()['configFilePath'] as string;\r\n\r\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\r\n inputFilePath,\r\n tsconfigFilePath\r\n );\r\n\r\n if (!packletAnalyzer.nothingToDo && !packletAnalyzer.error) {\r\n if (packletAnalyzer.isEntryPoint) {\r\n return {\r\n Program: (node: TSESTree.Node): void => {\r\n const readmePath: string = path.join(\r\n packletAnalyzer.packletsFolderPath!,\r\n packletAnalyzer.inputFilePackletName!,\r\n 'README.md'\r\n );\r\n try {\r\n if (!fs.existsSync(readmePath)) {\r\n context.report({\r\n node: node,\r\n messageId: 'missing-readme',\r\n data: { readmePath }\r\n });\r\n } else {\r\n if (minimumReadmeWords > 0) {\r\n const readmeContent: string = fs.readFileSync(readmePath).toString();\r\n const words: string[] = readmeContent.split(/[^a-z'\"]+/i).filter((x) => x.length > 0);\r\n if (words.length < minimumReadmeWords) {\r\n context.report({\r\n node: node,\r\n messageId: 'readme-too-short',\r\n data: { readmePath, minimumReadmeWords }\r\n });\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n context.report({\r\n node: node,\r\n messageId: 'error-reading-file',\r\n data: { readmePath, errorMessage: (error as Error).toString() }\r\n });\r\n }\r\n }\r\n };\r\n }\r\n }\r\n\r\n return {};\r\n }\r\n};\r\n\r\nexport { readme };\r\n"]}
1
+ {"version":3,"file":"readme.js","sourceRoot":"","sources":["../src/readme.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;;;;;;;;;;;;;;;;;;AAE3D,2CAA6B;AAC7B,uCAAyB;AAEzB,8EAAoE;AAEpE,uDAAoD;AASpD,MAAM,MAAM,GAA6C;IACvD,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,gBAAgB,EACd,wFAAwF;gBACxF,wCAAwC;YAC1C,kBAAkB,EAChB,iGAAiG;gBACjG,iCAAiC;YACnC,oBAAoB,EAAE,4DAA4D;SACnF;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,kBAAkB,EAAE;wBAClB,IAAI,EAAE,QAAQ;qBACf;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;QAED,IAAI,EAAE;YACJ,WAAW,EAAE,wFAAwF;YACrG,4DAA4D;YAC5D,QAAQ,EAAE,gBAAgB;YAC1B,4DAA4D;YAC5D,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,iEAAiE;SAC1C;KAC/B;IAED,MAAM,EAAE,CAAC,OAAkD,EAAE,EAAE;;QAC7D,MAAM,kBAAkB,GAAW,CAAA,MAAA,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,0CAAE,kBAAkB,KAAI,EAAE,CAAC;QAEhF,gEAAgE;QAChE,MAAM,aAAa,GAAW,OAAO,CAAC,WAAW,EAAE,CAAC;QAEpD,6CAA6C;QAC7C,MAAM,gBAAgB,GAAuB,gCAAW,CAAC,iBAAiB,CACxE,OAAO,CACR,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,gBAAgB,CAAW,CAAC;QAE3D,MAAM,eAAe,GAAoB,iCAAe,CAAC,gBAAgB,CACvE,aAAa,EACb,gBAAgB,CACjB,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;YAC1D,IAAI,eAAe,CAAC,YAAY,EAAE;gBAChC,OAAO;oBACL,OAAO,EAAE,CAAC,IAAmB,EAAQ,EAAE;wBACrC,MAAM,UAAU,GAAW,IAAI,CAAC,IAAI,CAClC,eAAe,CAAC,kBAAmB,EACnC,eAAe,CAAC,oBAAqB,EACrC,WAAW,CACZ,CAAC;wBACF,IAAI;4BACF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;gCAC9B,OAAO,CAAC,MAAM,CAAC;oCACb,IAAI,EAAE,IAAI;oCACV,SAAS,EAAE,gBAAgB;oCAC3B,IAAI,EAAE,EAAE,UAAU,EAAE;iCACrB,CAAC,CAAC;6BACJ;iCAAM;gCACL,IAAI,kBAAkB,GAAG,CAAC,EAAE;oCAC1B,MAAM,aAAa,GAAW,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;oCACrE,MAAM,KAAK,GAAa,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oCACtF,IAAI,KAAK,CAAC,MAAM,GAAG,kBAAkB,EAAE;wCACrC,OAAO,CAAC,MAAM,CAAC;4CACb,IAAI,EAAE,IAAI;4CACV,SAAS,EAAE,kBAAkB;4CAC7B,IAAI,EAAE,EAAE,UAAU,EAAE,kBAAkB,EAAE;yCACzC,CAAC,CAAC;qCACJ;iCACF;6BACF;yBACF;wBAAC,OAAO,KAAK,EAAE;4BACd,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,IAAI;gCACV,SAAS,EAAE,oBAAoB;gCAC/B,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAG,KAAe,CAAC,QAAQ,EAAE,EAAE;6BAChE,CAAC,CAAC;yBACJ;oBACH,CAAC;iBACF,CAAC;aACH;SACF;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC;AAEO,wBAAM","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport type { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\nimport { ESLintUtils } from '@typescript-eslint/experimental-utils';\n\nimport { PackletAnalyzer } from './PackletAnalyzer';\n\nexport type MessageIds = 'missing-readme' | 'error-reading-file' | 'readme-too-short';\ntype Options = [\n {\n minimumReadmeWords?: number;\n }\n];\n\nconst readme: TSESLint.RuleModule<MessageIds, Options> = {\n meta: {\n type: 'problem',\n messages: {\n 'missing-readme':\n 'The ESLint configuration requires each packlet to provide a README.md file summarizing' +\n ' its purpose and usage: {{readmePath}}',\n 'readme-too-short':\n 'The ESLint configuration requires at least {{minimumReadmeWords}} words of documentation in the' +\n ' README.md file: {{readmePath}}',\n 'error-reading-file': 'Error reading input file {{readmePath}}:\\n{{errorMessage}}'\n },\n schema: [\n {\n type: 'object',\n properties: {\n minimumReadmeWords: {\n type: 'number'\n }\n },\n additionalProperties: false\n }\n ],\n\n docs: {\n description: 'Require each packlet folder to have a README.md file summarizing its purpose and usage',\n // Deprecated in ESLint v8; Keep for backwards compatibility\n category: 'Best Practices',\n // Too strict to be recommended in the default configuration\n recommended: false,\n url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets'\n } as TSESLint.RuleMetaDataDocs\n },\n\n create: (context: TSESLint.RuleContext<MessageIds, Options>) => {\n const minimumReadmeWords: number = context.options[0]?.minimumReadmeWords || 10;\n\n // Example: /path/to/my-project/src/packlets/my-packlet/index.ts\n const inputFilePath: string = context.getFilename();\n\n // Example: /path/to/my-project/tsconfig.json\n const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices(\n context\n ).program.getCompilerOptions()['configFilePath'] as string;\n\n const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile(\n inputFilePath,\n tsconfigFilePath\n );\n\n if (!packletAnalyzer.nothingToDo && !packletAnalyzer.error) {\n if (packletAnalyzer.isEntryPoint) {\n return {\n Program: (node: TSESTree.Node): void => {\n const readmePath: string = path.join(\n packletAnalyzer.packletsFolderPath!,\n packletAnalyzer.inputFilePackletName!,\n 'README.md'\n );\n try {\n if (!fs.existsSync(readmePath)) {\n context.report({\n node: node,\n messageId: 'missing-readme',\n data: { readmePath }\n });\n } else {\n if (minimumReadmeWords > 0) {\n const readmeContent: string = fs.readFileSync(readmePath).toString();\n const words: string[] = readmeContent.split(/[^a-z'\"]+/i).filter((x) => x.length > 0);\n if (words.length < minimumReadmeWords) {\n context.report({\n node: node,\n messageId: 'readme-too-short',\n data: { readmePath, minimumReadmeWords }\n });\n }\n }\n }\n } catch (error) {\n context.report({\n node: node,\n messageId: 'error-reading-file',\n data: { readmePath, errorMessage: (error as Error).toString() }\n });\n }\n }\n };\n }\n }\n\n return {};\n }\n};\n\nexport { readme };\n"]}
package/package.json CHANGED
@@ -1,42 +1,45 @@
1
1
  {
2
- "name": "@rushstack/eslint-plugin-packlets",
3
- "version": "0.3.4",
4
- "description": "A lightweight alternative to NPM packages for organizing source files within a single project",
5
- "license": "MIT",
6
- "repository": {
7
- "url": "https://github.com/microsoft/rushstack.git",
8
- "type": "git",
9
- "directory": "stack/eslint-plugin-packlets"
10
- },
11
- "homepage": "https://rushstack.io",
12
- "keywords": [
13
- "eslint",
14
- "eslint-config",
15
- "packlets",
16
- "rules"
17
- ],
18
- "main": "lib/index.js",
19
- "typings": "lib/index.d.ts",
20
- "dependencies": {
21
- "@rushstack/tree-pattern": "0.2.2",
22
- "@typescript-eslint/experimental-utils": "~5.3.0"
23
- },
24
- "peerDependencies": {
25
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
26
- },
27
- "devDependencies": {
28
- "@rushstack/heft": "0.42.3",
29
- "@rushstack/heft-node-rig": "1.2.32",
30
- "@types/eslint": "8.2.0",
31
- "@types/estree": "0.0.50",
32
- "@types/heft-jest": "1.0.1",
33
- "@types/node": "12.20.24",
34
- "@typescript-eslint/parser": "~5.3.0",
35
- "@typescript-eslint/typescript-estree": "~5.3.0",
36
- "eslint": "~8.3.0",
37
- "typescript": "~4.4.2"
38
- },
39
- "scripts": {
40
- "build": "heft test --clean"
41
- }
42
- }
2
+ "name": "@rushstack/eslint-plugin-packlets",
3
+ "version": "0.3.5",
4
+ "description": "A lightweight alternative to NPM packages for organizing source files within a single project",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "url": "https://github.com/microsoft/rushstack.git",
8
+ "type": "git",
9
+ "directory": "eslint/eslint-plugin-packlets"
10
+ },
11
+ "homepage": "https://rushstack.io",
12
+ "keywords": [
13
+ "eslint",
14
+ "eslint-config",
15
+ "packlets",
16
+ "rules"
17
+ ],
18
+ "main": "lib/index.js",
19
+ "typings": "lib/index.d.ts",
20
+ "dependencies": {
21
+ "@rushstack/tree-pattern": "0.2.2",
22
+ "@typescript-eslint/experimental-utils": "~5.6.0"
23
+ },
24
+ "peerDependencies": {
25
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@rushstack/heft": "0.44.2",
29
+ "@rushstack/heft-node-rig": "1.7.1",
30
+ "@types/eslint": "8.2.0",
31
+ "@types/estree": "0.0.50",
32
+ "@types/heft-jest": "1.0.1",
33
+ "@types/node": "12.20.24",
34
+ "@typescript-eslint/parser": "~5.6.0",
35
+ "@typescript-eslint/typescript-estree": "~5.6.0",
36
+ "eslint": "~8.7.0",
37
+ "typescript": "~4.5.2"
38
+ },
39
+ "scripts": {
40
+ "build": "heft build --clean",
41
+ "_phase:build": "heft build --clean",
42
+ "_phase:test": "heft test --no-build"
43
+ },
44
+ "readme": "# @rushstack/eslint-plugin-packlets\n\nPacklets provide a lightweight alternative to NPM packages for organizing source files within a single project. The formalism is validated using ESLint rules.\n\n## Motivation\n\nWhen building a large application, it's a good idea to organize source files into modules, so that their dependencies can be managed. For example, suppose an application's source files can be grouped as follows:\n\n- `src/logging/*.ts` - the logging system\n- `src/data-model/*.ts` - the data model\n- `src/reports/*.ts` - the report engine\n- `src/*.ts` - other arbitrary files such as startup code and the main application\n\nUsing file folders is helpful, but it's not very strict. Files under `src/logging` can easily import files from `/src/reports`, creating a confusing circular import. They can also import arbitrary application files. Also, there is no clear distinction between which files are the \"public API\" for `src/logging` versus its private implementation details.\n\nAll these problems can be solved by reorganizing the project into NPM packages (or [Rush projects](https://rushjs.io/)). Something like this:\n\n- `@my-app/logging` - the logging system\n- `@my-app/data-model` - the data model\n- `@my-app/reports` - the report engine\n- `@my-app/application` - other arbitrary files such as startup code and the main application\n\nHowever, separating code in this way has some downsides. The projects need to build separately, which has some tooling costs (for example, \"watch mode\" now needs to consider multiple projects). In a large monorepo, the library may attract other consumers, before the API has been fully worked out.\n\nPacklets provide a lightweight alternative that offers many of the same benefits of packages, but without the `package.json` file. It's a great way to prototype your project organization before later graduating your packlets into proper NPM packages.\n\n## 5 rules for packlets\n\nWith packlets, our folders would be reorganized as follows:\n\n- `src/packlets/logging/*.ts` - the logging system\n- `src/packlets/data-model/*.ts` - the data model\n- `src/packlets/reports/*.ts` - the report engine\n- `src/*.ts` - other arbitrary files such as startup code and the main application\n\nThe [packlets-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/other/packlets-tutorial) sample project illustrates this layout in full detail.\n\nThe basic design can be summarized in 5 rules:\n\n1. A \"packlet\" is defined to be a folder path `./src/packlets/<packlet-name>/index.ts`. The **index.ts** file will have the exported APIs. The `<packlet-name>` name must consist of lower case words separated by hyphens, similar to an NPM package name.\n\n Example file paths:\n ```\n src/packlets/controls\n src/packlets/logger\n src/packlets/my-long-name\n ```\n\n > **NOTE:** The `packlets` cannot be nested deeper in the tree. Like with NPM packages, `src/packlets` is a flat namespace.\n\n2. Files outside the packlet folder can only import the packlet root **index.ts**:\n\n **src/app/App.ts**\n ```ts\n // Okay\n import { MainReport } from '../packlets/reports';\n\n // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)\n import { MainReport } from '../packlets/reports/index';\n\n // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)\n import { MainReport } from '../packlets/reports/MainReport';\n ```\n\n3. Files inside a packlet folder should import their siblings directly, not via their own **index.ts** (which might create a circular reference):\n\n **src/packlets/logging/Logger.ts**\n ```ts\n // Okay\n import { MessageType } from \"./MessageType\";\n\n // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)\n import { MessageType } from \".\";\n\n // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)\n import { MessageType} from \"./index\";\n ```\n\n\n4. Packlets may reference other packlets, but not in a way that would introduce a circular dependency:\n\n **src/packlets/data-model/DataModel.ts**\n ```ts\n // Okay\n import { Logger } from '../../packlets/logging';\n ```\n\n **src/packlets/logging/Logger.ts**\n ```ts\n // Error: Packlet imports create a circular reference: (@rushstack/packlets/circular-deps)\n // \"logging\" is referenced by src/packlets/data-model/DataModel.ts\n // \"data-model\" is referenced by src/packlets/logging/Logger.ts\n import { DataModel } from '../../packlets/data-model';\n ```\n\n5. Other source files are allowed outside the **src/packlets** folder. They may import a packlet, but packlets must only import from other packlets or NPM packages.\n\n **src/app/App.ts**\n\n ```ts\n // Okay\n import { MainReport } from '../packlets/reports';\n ```\n\n **src/packlets/data-model/ExampleModel.ts**\n ```ts\n // Error: A local project file cannot be imported. A packlet's dependencies must be\n // NPM packages and/or other packlets. (@rushstack/packlets/mechanics)\n import { App } from '../../app/App';\n ```\n\n\n## Getting Started\n\nTo enable packlet validation for a simple `typescript-eslint` setup, reference the `@rushstack/eslint-plugin-packlets` project like this:\n\n**\\<my-project\\>/.eslintrc.js**\n```js\nmodule.exports = {\n root: true,\n parser: '@typescript-eslint/parser',\n plugins: ['@typescript-eslint'],\n extends: [\n 'eslint:recommended',\n 'plugin:@typescript-eslint/recommended',\n 'plugin:@rushstack/eslint-plugin-packlets/recommended' // <--- ADD THIS\n ],\n parserOptions: {\n project: './tsconfig.json',\n sourceType: 'module',\n tsconfigRootDir: __dirname\n }\n};\n```\n\nOr, if you are using the [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) ruleset, add the `\"packlets\"` mixin like this:\n\n**\\<my-project\\>/.eslintrc.js**\n```ts\n// This is a workaround for https://github.com/eslint/eslint/issues/3458\nrequire('@rushstack/eslint-config/patch/modern-module-resolution');\n\nmodule.exports = {\n extends: [\n \"@rushstack/eslint-config/profile/node\",\n \"@rushstack/eslint-config/mixins/packlets\" // <--- ADD THIS\n ],\n parserOptions: { tsconfigRootDir: __dirname }\n};\n```\n\nThe `@rushstack/eslint-plugin-packlets` plugin implements three separate rules:\n\n- `@rushstack/packlets/mechanics` - validates most of the import path rules outlined above.\n- `@rushstack/packlets/circular-deps` - detects circular dependencies between packlets. This rule requires an ESLint configuration that enables full type information from the TypeScript compiler.\n- `@rushstack/packlets/readme` - requires each packlet to have a README.md file. This rule is disabled by default.\n\n## Requiring a README.md file\n\nIf you'd like to require a README.md file in each packlet folder, enable the optional `@rushstack/packlets/readme` rule.\n\nThe `minimumReadmeWords` option allows you to specify a minimum number of words of documentation in the README.md file. The default value is `10` words.\n\nExample configuration with the `@rushstack/packlets/readme` rule enabled:\n\n**\\<my-project\\>/.eslintrc.js**\n```ts\n// This is a workaround for https://github.com/eslint/eslint/issues/3458\nrequire('@rushstack/eslint-config/patch/modern-module-resolution');\n\nmodule.exports = {\n extends: [\n \"@rushstack/eslint-config/profile/node\",\n \"@rushstack/eslint-config/mixins/packlets\"\n ],\n parserOptions: { tsconfigRootDir: __dirname },\n overrides: [\n {\n files: ['*.ts', '*.tsx'],\n\n rules: {\n '@rushstack/packlets/readme': [ // <--- ADD THIS\n 'warn',\n { minimumReadmeWords: 10 }\n ]\n }\n }\n ]\n};\n```\n\n## Links\n\n- [CHANGELOG.md](\n https://github.com/microsoft/rushstack/blob/master/stack/eslint-plugin-packlets/CHANGELOG.md) - Find\n out what's new in the latest version\n- [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) documentation\n\n`@rushstack/eslint-plugin-packlets` is part of the [Rush Stack](https://rushstack.io/) family of projects.\nThe idea for packlets was originally proposed by [@bartvandenende-wm](https://github.com/bartvandenende-wm)\nand [@victor-wm](https://github.com/victor-wm).\n"
45
+ }
package/CHANGELOG.json DELETED
@@ -1,148 +0,0 @@
1
- {
2
- "name": "@rushstack/eslint-plugin-packlets",
3
- "entries": [
4
- {
5
- "version": "0.3.4",
6
- "tag": "@rushstack/eslint-plugin-packlets_v0.3.4",
7
- "date": "Mon, 06 Dec 2021 16:08:32 GMT",
8
- "comments": {
9
- "patch": [
10
- {
11
- "comment": "Add support for ESLint v8"
12
- }
13
- ]
14
- }
15
- },
16
- {
17
- "version": "0.3.3",
18
- "tag": "@rushstack/eslint-plugin-packlets_v0.3.3",
19
- "date": "Wed, 27 Oct 2021 00:08:15 GMT",
20
- "comments": {
21
- "patch": [
22
- {
23
- "comment": "Update the package.json repository field to include the directory property."
24
- }
25
- ],
26
- "dependency": [
27
- {
28
- "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.2`"
29
- }
30
- ]
31
- }
32
- },
33
- {
34
- "version": "0.3.2",
35
- "tag": "@rushstack/eslint-plugin-packlets_v0.3.2",
36
- "date": "Thu, 07 Oct 2021 07:13:35 GMT",
37
- "comments": {
38
- "patch": [
39
- {
40
- "comment": "Update typescript-eslint to add support for TypeScript 4.4."
41
- }
42
- ]
43
- }
44
- },
45
- {
46
- "version": "0.3.1",
47
- "tag": "@rushstack/eslint-plugin-packlets_v0.3.1",
48
- "date": "Thu, 23 Sep 2021 00:10:40 GMT",
49
- "comments": {
50
- "patch": [
51
- {
52
- "comment": "Upgrade the `@types/node` dependency to version to version 12."
53
- }
54
- ]
55
- }
56
- },
57
- {
58
- "version": "0.3.0",
59
- "tag": "@rushstack/eslint-plugin-packlets_v0.3.0",
60
- "date": "Mon, 12 Jul 2021 23:08:26 GMT",
61
- "comments": {
62
- "minor": [
63
- {
64
- "comment": "Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)"
65
- }
66
- ]
67
- }
68
- },
69
- {
70
- "version": "0.2.2",
71
- "tag": "@rushstack/eslint-plugin-packlets_v0.2.2",
72
- "date": "Mon, 12 Apr 2021 15:10:28 GMT",
73
- "comments": {
74
- "patch": [
75
- {
76
- "comment": "Fix an issue where the @rushstack/packlets/circular-deps rule did not work correctly with TypeScript 4.2"
77
- }
78
- ]
79
- }
80
- },
81
- {
82
- "version": "0.2.1",
83
- "tag": "@rushstack/eslint-plugin-packlets_v0.2.1",
84
- "date": "Tue, 06 Apr 2021 15:14:22 GMT",
85
- "comments": {
86
- "patch": [
87
- {
88
- "comment": "Fix unlisted dependency on @typescript-eslint/experimental-utils"
89
- }
90
- ]
91
- }
92
- },
93
- {
94
- "version": "0.2.0",
95
- "tag": "@rushstack/eslint-plugin-packlets_v0.2.0",
96
- "date": "Wed, 11 Nov 2020 01:08:58 GMT",
97
- "comments": {
98
- "minor": [
99
- {
100
- "comment": "Add an optional \"@rushstack/packlets/readme\" rule that requires a README.md in each packlet folder"
101
- }
102
- ]
103
- }
104
- },
105
- {
106
- "version": "0.1.2",
107
- "tag": "@rushstack/eslint-plugin-packlets_v0.1.2",
108
- "date": "Wed, 28 Oct 2020 01:18:03 GMT",
109
- "comments": {
110
- "patch": [
111
- {
112
- "comment": "Fix an exception that occured if a source file was added to the \"src/packlets\" folder, not belonging to any packlet"
113
- },
114
- {
115
- "comment": "Fix an issue where linting was sometimes not performed on MacOS, because Node.js \"path.relative()\" incorrectly assumes that every POSIX file system is case-sensitive"
116
- },
117
- {
118
- "comment": "Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies"
119
- }
120
- ]
121
- }
122
- },
123
- {
124
- "version": "0.1.1",
125
- "tag": "@rushstack/eslint-plugin-packlets_v0.1.1",
126
- "date": "Tue, 06 Oct 2020 00:24:06 GMT",
127
- "comments": {
128
- "patch": [
129
- {
130
- "comment": "Fix broken link to tutorial project in README.md"
131
- }
132
- ]
133
- }
134
- },
135
- {
136
- "version": "0.1.0",
137
- "tag": "@rushstack/eslint-plugin-packlets_v0.1.0",
138
- "date": "Mon, 05 Oct 2020 22:36:57 GMT",
139
- "comments": {
140
- "minor": [
141
- {
142
- "comment": "Initial release"
143
- }
144
- ]
145
- }
146
- }
147
- ]
148
- }
package/CHANGELOG.md DELETED
@@ -1,83 +0,0 @@
1
- # Change Log - @rushstack/eslint-plugin-packlets
2
-
3
- This log was last generated on Mon, 06 Dec 2021 16:08:32 GMT and should not be manually modified.
4
-
5
- ## 0.3.4
6
- Mon, 06 Dec 2021 16:08:32 GMT
7
-
8
- ### Patches
9
-
10
- - Add support for ESLint v8
11
-
12
- ## 0.3.3
13
- Wed, 27 Oct 2021 00:08:15 GMT
14
-
15
- ### Patches
16
-
17
- - Update the package.json repository field to include the directory property.
18
-
19
- ## 0.3.2
20
- Thu, 07 Oct 2021 07:13:35 GMT
21
-
22
- ### Patches
23
-
24
- - Update typescript-eslint to add support for TypeScript 4.4.
25
-
26
- ## 0.3.1
27
- Thu, 23 Sep 2021 00:10:40 GMT
28
-
29
- ### Patches
30
-
31
- - Upgrade the `@types/node` dependency to version to version 12.
32
-
33
- ## 0.3.0
34
- Mon, 12 Jul 2021 23:08:26 GMT
35
-
36
- ### Minor changes
37
-
38
- - Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)
39
-
40
- ## 0.2.2
41
- Mon, 12 Apr 2021 15:10:28 GMT
42
-
43
- ### Patches
44
-
45
- - Fix an issue where the @rushstack/packlets/circular-deps rule did not work correctly with TypeScript 4.2
46
-
47
- ## 0.2.1
48
- Tue, 06 Apr 2021 15:14:22 GMT
49
-
50
- ### Patches
51
-
52
- - Fix unlisted dependency on @typescript-eslint/experimental-utils
53
-
54
- ## 0.2.0
55
- Wed, 11 Nov 2020 01:08:58 GMT
56
-
57
- ### Minor changes
58
-
59
- - Add an optional "@rushstack/packlets/readme" rule that requires a README.md in each packlet folder
60
-
61
- ## 0.1.2
62
- Wed, 28 Oct 2020 01:18:03 GMT
63
-
64
- ### Patches
65
-
66
- - Fix an exception that occured if a source file was added to the "src/packlets" folder, not belonging to any packlet
67
- - Fix an issue where linting was sometimes not performed on MacOS, because Node.js "path.relative()" incorrectly assumes that every POSIX file system is case-sensitive
68
- - Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies
69
-
70
- ## 0.1.1
71
- Tue, 06 Oct 2020 00:24:06 GMT
72
-
73
- ### Patches
74
-
75
- - Fix broken link to tutorial project in README.md
76
-
77
- ## 0.1.0
78
- Mon, 05 Oct 2020 22:36:57 GMT
79
-
80
- ### Minor changes
81
-
82
- - Initial release
83
-