Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
import fs from "fs";
import { kebabToCamelCase } from "./utils/kebabToKamelCase";

function transformer(file, api, options) {
// @ts-ignore: No types for jscodeshift
import { FileInfo, API, Options } from "jscodeshift";

interface TransformerOptions {
ruleName: string;
exportIndexFilePath: string;
}

export function transformer(file: FileInfo, api: API, options: TransformerOptions): string {
const j = api.jscodeshift;
const { ruleName, exportIndexFilePath } = options;

Expand Down Expand Up @@ -45,14 +53,15 @@ function transformer(file, api, options) {
// Manually sort the export statements alphabetically
const sortedExports = updatedExportStatements
.nodes()
.map(node => {

.map((node: any) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid 'any' and use the types. import { TSESTree } from "@typescript-eslint/utils"; that package should have the right types.

if (node.specifiers && node.specifiers[0] && node.specifiers[0].exported) {
return node;
}
return null; // Ignore nodes without valid specifiers
})
.filter(node => node !== null) // Remove nulls
.sort((a, b) => {
.filter((node: any) => node !== null) // Remove nulls
.sort((a: any, b: any) => {
const aName = a.specifiers[0].exported.name;
const bName = b.specifiers[0].exported.name;
return aName.localeCompare(bName);
Expand All @@ -63,7 +72,7 @@ function transformer(file, api, options) {

// Now insert the sorted export statements back into the AST
const body = exportIndexSource.get().node.program.body;
sortedExports.forEach(exportNode => {
sortedExports.forEach((exportNode: any) => {
body.push(exportNode); // Insert each export statement at the end of the body
});
}
Expand All @@ -74,4 +83,4 @@ function transformer(file, api, options) {
// Return the original file source (this is for the main file passed in)
return file.source;
}
module.exports = transformer;

22 changes: 13 additions & 9 deletions scripts/addRuleToIndex.js → scripts/addRuleToIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,29 @@
import { kebabToCamelCase } from "./utils/kebabToKamelCase";

// Sort function to keep rules and config sorted alphabetically
const nameSort = (a, b) => {
const nameSort = (a: any, b: any) => {
const aName = a.key.type === "Literal" ? a.key.value : a.key.name;
const bName = a.key.type === "Literal" ? b.key.value : b.key.name;
const bName = b.key.type === "Literal" ? b.key.value : b.key.name;
if (aName < bName) return -1;
if (aName > bName) return 1;
return 0;
};

const transformer = (file, api, options) => {
interface TransformerOptions {
ruleName: string;
}

export const transformer = (file: any, api: any, options: any): string | null => {
const j = api.jscodeshift;
const root = j(file.source);
const { ruleName } = options; // No need for rulePath in this case
const { ruleName } = options;

let changesMade = 0;

// Step 1: Add rule to the `rules` object (without parentheses)
root.find(j.Property, { key: { name: "rules" } })
.at(0)
.forEach(path => {
.forEach((path: any) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any in this file too

const properties = path.value.value.properties;
properties.unshift(
j.property("init", j.literal(ruleName), j.memberExpression(j.identifier("rules"), j.identifier(kebabToCamelCase(ruleName))))
Expand All @@ -32,11 +36,11 @@ const transformer = (file, api, options) => {
});

// Step 2: Find and modify `configs.recommended.rules`
root.find(j.Property, { key: { name: "configs" } }).forEach(configPath => {
const recommendedConfig = configPath.value.value.properties.find(prop => prop.key.name === "recommended");
root.find(j.Property, { key: { name: "configs" } }).forEach((configPath: any) => {
const recommendedConfig = configPath.value.value.properties.find((prop: any) => prop.key.name === "recommended");

if (recommendedConfig) {
const recommendedRules = recommendedConfig.value.properties.find(prop => prop.key.name === "rules");
const recommendedRules = recommendedConfig.value.properties.find((prop: any) => prop.key.name === "rules");

if (recommendedRules) {
const rulesProps = recommendedRules.value.properties;
Expand All @@ -53,4 +57,4 @@ const transformer = (file, api, options) => {

return root.toSource({ quote: "double", trailingComma: false });
};
module.exports = transformer;

7 changes: 5 additions & 2 deletions scripts/boilerplate/doc.js → scripts/boilerplate/doc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const docBoilerplateGenerator = (name, description) => `# ${description} (@microsoft/fluentui-jsx-a11y/${name})
export const docBoilerplateGenerator = (
name: string,
description: string
): string => `# ${description} (@microsoft/fluentui-jsx-a11y/${name})

Write a useful explanation here!

Expand All @@ -19,4 +22,4 @@ Write more details here!

## Further Reading
`;
module.exports = docBoilerplateGenerator;

4 changes: 2 additions & 2 deletions scripts/boilerplate/rule.js → scripts/boilerplate/rule.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const ruleBoilerplate = (name, description) => `// Copyright (c) Microsoft Corporation.
export const ruleBoilerplateGenerator = (name: string, description: string): string => `// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
Expand Down Expand Up @@ -42,4 +42,4 @@ const rule = createRule({

export default rule;
`;
module.exports = ruleBoilerplate;

4 changes: 2 additions & 2 deletions scripts/boilerplate/test.js → scripts/boilerplate/test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const testBoilerplate = name => `// Copyright (c) Microsoft Corporation.
export const testBoilerplateGenerator = (name: string): string => `// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Rule } from "eslint";
Expand All @@ -21,4 +21,4 @@ ruleTester.run("${name}", rule as unknown as Rule.RuleModule, {
]
});
`;
module.exports = testBoilerplate;

25 changes: 13 additions & 12 deletions scripts/create-rule.js → scripts/create-rule.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test this script with the repo create command? I think you need to update the package.json script to run ts-node instead of node since node doesn't natively work with TypeScript (at least with the versions we're using).

ex. npm run create -- rule-name

Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
// Licensed under the MIT License.

/* eslint-disable no-console */
const { resolve } = require("path");
const { existsSync, writeFileSync } = require("fs");
const { exec } = require("child_process");
const yargs = require("yargs/yargs"); // Use yargs/yargs for modules
const { hideBin } = require("yargs/helpers"); // To handle CLI arguments
const ruleBoilerplateGenerator = require("./boilerplate/rule");
const testBoilerplateGenerator = require("./boilerplate/test");
const docBoilerplateGenerator = require("./boilerplate/doc");
import { resolve } from "path";
import { existsSync, writeFileSync } from "fs";
import { exec } from "child_process";
import yargs from "yargs/yargs";
import { hideBin } from "yargs/helpers";
import {ruleBoilerplateGenerator} from "./boilerplate/rule";
import {testBoilerplateGenerator} from "./boilerplate/test";
import {docBoilerplateGenerator} from "./boilerplate/doc";

// Define the yargs configuration
const argv = yargs(hideBin(process.argv))
Expand All @@ -27,11 +27,11 @@ const argv = yargs(hideBin(process.argv))
default: "$DESCRIPTION" // Provide default value
}
})
.demandCommand(1, "You must provide the rule name.").argv; // Make the rule name (positional)
.demandCommand(1, "You must provide the rule name.").argv as any; // Type assertion for yargs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per Aubrey's other comments, any usage should be avoided.

See the yargs docs for how to avoid this casting. Since there's no async processes occurring, you can replace argv with parseSync(). https://github.com/yargs/yargs/blob/HEAD/docs/typescript.md#typescript-usage-examples


const ruleName = argv._[0];
const author = argv.author || "$AUTHOR";
const description = argv.description || "$DESCRIPTION";
const ruleName: string = argv._[0];
const author: string = argv.author || "$AUTHOR";
const description: string = argv.description || "$DESCRIPTION";

const rulePath = resolve(`lib/rules/${ruleName}.ts`);
const testPath = resolve(`tests/lib/rules/${ruleName}-test.ts`);
Expand Down Expand Up @@ -106,3 +106,4 @@ exec(commandForMainIndex, (error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
});
});

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export const kebabToCamelCase = str => {
export const kebabToCamelCase = (str: string): string => {
return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase()).replace(/^(.)/, (_, char) => char.toLowerCase());
};

Loading