Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ESLint Plugin] Enforce inclusion of dist-esm and exclusion of src in files field in package.json #11411

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12,49 +12,33 @@ This rule is fixable using the `--fix` option.

```json
{
"files": [
"dist",
"dist-esm/src"
"src"
]
"files": ["dist", "dist-esm/src"]
}
```

```json
{
"files": [
"./dist",
"./dist-esm/src"
"./src"
]
"files": ["./dist", "./dist-esm/src"]
}
```

```json
{
"files": [
"dist/",
"dist-esm/src/"
"src/"
]
"files": ["dist/", "dist-esm/"]
}
```

```json
{
"files": [
"dist/lib",
"dist-esm/src/lib"
"src/lib"
]
"files": ["dist/lib", "dist-esm/src/lib"]
}
```

### Bad

```json
{
"files": ["dist", "dist-esm/src"]
"files": ["dist", "src"]
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

/**
* @file Rule to force package.json's files value to contain paths to the package contents.
* @file Rule to force package.json's files value to contain paths to the package contents and excludes source code files.
* @author Arpan Laha
*/

Expand All @@ -13,6 +13,26 @@ import { arrayToString, getRuleMetaData, getVerifiers, stripPath } from "../util
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
interface HashTable<T> {
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
[key: string]: T;
}
let requiredPatternSuggestionMap: HashTable<string | undefined> = {};
function addRequiredPattern(pattern: string, suggestion?: string): void {
requiredPatternSuggestionMap[pattern] = suggestion;
}

/**
* The rule is configurable by those two vars, where badPatterns is the list of
* patterns that should not be in package.json's files list and requiredPatterns
* is the list of patterns that should be.
*/
const badPatterns: string[] = ["src"];
const requiredPatterns: string[] = [];
addRequiredPattern("dist");
addRequiredPattern("dist-esm", "src");
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
for (const pat in requiredPatternSuggestionMap) {
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
requiredPatterns.push(pat);
}

export = {
meta: getRuleMetaData(
Expand All @@ -24,14 +44,20 @@ export = {
const verifiers = getVerifiers(context, {
outer: "files"
});
// sorting the patterns descendingly so in cases of overlap between patterns
// (e.g. dist and dist-esm), the regex tries to match the longer first.
const regExprStr = `^(?:.\/)?(${badPatterns
.concat(requiredPatterns)
.sort()
.reverse()
.join("|")})(?:\/)?(?:.+)?`;
return stripPath(context.getFilename()) === "package.json"
? ({
// callback functions

// check to see if files exists at the outermost level
"ExpressionStatement > ObjectExpression": verifiers.existsInFile,

// check that files contains dist, dist-esm, and src
"ExpressionStatement > ObjectExpression > Property[key.value='files']": (
node: Property
): void => {
Expand All @@ -46,37 +72,54 @@ export = {

const nodeValue = node.value;
const elements = nodeValue.elements as Literal[];
const elementValues = elements.map((element: Literal): unknown => element.value);
let elementValues = elements.map((element: Literal): unknown => element.value);

// looks for 'dist' with optional leading './' and optional trailing '/'
if (
elements.every(
(element: Literal): boolean =>
!/^(.\/)?((dist\/)|(dist$))/.test(element.value as string)
)
) {
context.report({
node: nodeValue,
message: "dist is not included in files",
fix: (fixer: Rule.RuleFixer): Rule.Fix => {
elementValues.push("dist");
return fixer.replaceText(nodeValue, arrayToString(elementValues));
let currBadPatterns: string[] = [];
let currRequiredPatterns = [...requiredPatterns];
const fullMatchIndex = 0;
const patternRootMatchIndex = 1;
elements.forEach((element) => {
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
const patternMatchResult = (element.value as string).match(regExprStr);
if (patternMatchResult !== null) {
const patternRoot = patternMatchResult[patternRootMatchIndex];
if (badPatterns.indexOf(patternRoot) >= 0) {
deyaaeldeen marked this conversation as resolved.
Show resolved Hide resolved
currBadPatterns.push(patternMatchResult[fullMatchIndex]);
} else if (requiredPatterns.indexOf(patternRoot) >= 0) {
currRequiredPatterns.splice(currRequiredPatterns.indexOf(patternRoot), 1);
}
});
}
});
let message = "";
if (currBadPatterns.length > 0) {
message = `${currBadPatterns.join()} ${
currBadPatterns.length === 1 ? "is" : "are"
} included in files`;
elementValues = elementValues.filter(
(element) => currBadPatterns.indexOf(element as string) < 0
);
}

// looks for 'dist-esm/src' with optional leading './' and optional trailing '/'
if (
elements.every(
(element: Literal): boolean =>
!/^(.\/)?dist-esm\/((src\/)|(src$))/.test(element.value as string)
)
) {
if (currRequiredPatterns.length > 0) {
for (let i = 0; i < currRequiredPatterns.length; ++i) {
const pat = currRequiredPatterns[i];
if (requiredPatternSuggestionMap[pat] !== undefined) {
currRequiredPatterns[i] = pat + "/" + requiredPatternSuggestionMap[pat];
}
}
elementValues = elementValues.concat(currRequiredPatterns);
if (message.length > 0) {
message = message + " and ";
}
message =
message +
`${currRequiredPatterns.join()} ${
currRequiredPatterns.length === 1 ? "is" : "are"
} not included in files`;
}
if (message.length > 0) {
context.report({
node: nodeValue,
message: "dist-esm/src is not included in files",
message: message,
fix: (fixer: Rule.RuleFixer): Rule.Fix => {
elementValues.push("dist-esm/src");
return fixer.replaceText(nodeValue, arrayToString(elementValues));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,20 +309,20 @@ ruleTester.run("ts-package-json-files-required", rule, {
filename: "package.json",
errors: [
{
message: "dist-esm/src is not included in files"
message: "src is included in files and dist-esm/src is not included in files"
}
],
output: '{"files": ["dist", "src", "dist-esm/src"]}'
output: '{"files": ["dist", "dist-esm/src"]}'
},
{
code: '{"files": ["src", "dist-esm/src"]}',
filename: "package.json",
errors: [
{
message: "dist is not included in files"
message: "src is included in files and dist is not included in files"
}
],
output: '{"files": ["src", "dist-esm/src", "dist"]}'
output: '{"files": ["dist-esm/src", "dist"]}'
},
{
code: '{"files": ["dist"]}',
Expand All @@ -349,26 +349,20 @@ ruleTester.run("ts-package-json-files-required", rule, {
filename: "package.json",
errors: [
{
message: "dist is not included in files"
},
{
message: "dist-esm/src is not included in files"
message: "dist,dist-esm/src are not included in files"
}
],
output: '{"files": ["dist"]}'
output: '{"files": ["dist", "dist-esm/src"]}'
},
{
// example file with src not in files
code: examplePackageBad,
filename: "package.json",
errors: [
{
message: "dist is not included in files"
},
{
message: "dist-esm/src is not included in files"
message: "dist,dist-esm/src are not included in files"
}
]
}
]
});
});
1 change: 0 additions & 1 deletion sdk/storage/storage-datalake/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"esm/**/*.js.map",
"esm/**/*.d.ts",
"esm/**/*.d.ts.map",
"src/**/*.ts",
"README.md",
"rollup.config.js",
"tsconfig.json"
Expand Down