Skip to content
Merged
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
2 changes: 0 additions & 2 deletions .eslintignore

This file was deleted.

21 changes: 0 additions & 21 deletions .eslintrc

This file was deleted.

28 changes: 11 additions & 17 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@ jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [ 14.x ]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 20.x
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run test
Expand All @@ -33,16 +30,13 @@ jobs:
needs: [test]
if: ${{ github.event_name != 'pull_request' && (contains(github.ref, 'master') || contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc')) }}

strategy:
matrix:
node-version: [ 14.x ]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 20.x
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Release packages
Expand All @@ -51,7 +45,7 @@ jobs:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: yarn release
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v4
with:
name: packages
path: |
Expand Down
4 changes: 1 addition & 3 deletions .mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@ process.env.NODE_ENV = "test";
module.exports = {
recursive: true,
reporter: "dot",
spec: [
"packages/**/*.spec.js"
]
spec: ["packages/**/*.spec.js"]
};
62 changes: 62 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import typescriptParser from "@typescript-eslint/parser";
import pluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import globals from "globals";
import {join} from "node:path";

export default [
{
ignores: [
"**/coverage",
"**/lib",
"**/dist",
"processes.config.js",
"**/snapshots",
"**/templates",
"**/docs/**",
"**/docs-references/**"
]
},
{
files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider separating TypeScript and JavaScript patterns.

For better maintainability, consider splitting the file patterns:

-    files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
+    files: [
+      "**/*.{js,mjs,cjs,jsx,mjsx}",  // JavaScript files
+      "**/*.{ts,tsx,mtsx}"           // TypeScript files
+    ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
files: [
"**/*.{js,mjs,cjs,jsx,mjsx}", // JavaScript files
"**/*.{ts,tsx,mtsx}" // TypeScript files
],

languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: typescriptParser,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module"
},
globals: {
...globals.node
}
},
plugins: {
"@typescript-eslint": typescriptEslint
},
rules: {
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-unused-vars": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0
}
Comment on lines +37 to +46
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Enable TypeScript ESLint rules for better code quality

The project heavily uses TypeScript as evidenced by:

  • Numerous .d.ts files in the codebase
  • TypeScript dependencies in package.json
  • TypeScript parser and plugin configuration in ESLint

Consider enabling these essential rules with at least warning level (1):

  • @typescript-eslint/no-explicit-any: Prevents the use of unsafe any type
  • @typescript-eslint/no-unused-vars: Catches dead code and typos
  • @typescript-eslint/explicit-module-boundary-types: Ensures better API documentation
  • @typescript-eslint/no-non-null-assertion: Prevents potential runtime errors

The other disabled rules can remain at 0 if they conflict with your coding standards.

🔗 Analysis chain

Review disabled TypeScript rules.

Disabling all TypeScript rules (0) might lead to code quality issues. Consider:

  1. Enabling essential rules like no-explicit-any and no-unused-vars
  2. Using warning level (1) instead of completely disabling rules
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any TypeScript files in the project
fd -e ts -e tsx

# If TypeScript files exist, we should have stricter rules
if [ $? -eq 0 ]; then
  echo "TypeScript files found. Consider enabling essential TypeScript rules."
fi

Length of output: 485


Script:

#!/bin/bash
# Let's check for TypeScript files more thoroughly
rg --type-list | grep -i typescript
echo "=== Checking for TypeScript files ==="
find . -type f -name "*.ts" -o -name "*.tsx" 2>/dev/null

echo -e "\n=== Checking package.json for TypeScript ==="
rg "typescript" package.json

echo -e "\n=== Checking for tsconfig.json ==="
find . -name "tsconfig*.json" 2>/dev/null

echo -e "\n=== Checking current ESLint configuration ==="
cat eslint.config.mjs

Length of output: 9609

},
// {
// files: ["**/*.spec.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"], // or any other pattern
// ignores: ["docs/**", "docs-references/**"],
// plugins: {
// vitest
// },
// rules: {
// ...vitest.configs.recommended.rules, // you can also use vitest.configs.all.rules to enable all rules
// "vitest/consistent-test-it": ["error", {fn: "it", withinDescribe: "it"}],
// "vitest/no-alias-methods": "error",
// "vitest/expect-expect": "off"
// }
// },
pluginPrettierRecommended
];
20 changes: 12 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"test": "yarn test:lint && yarn test:coverage",
"test:unit": "cross-env NODE_ENV=test mocha",
"test:coverage": "cross-env NODE_ENV=test nyc mocha",
"test:lint": "eslint packages --ext .js",
"test:lint:fix": "eslint packages --ext .js --fix",
"test:lint": "eslint",
"test:lint:fix": "eslint --fix",
"build": "monorepo build",
"sync:packages": "monorepo sync packages",
"release": "semantic-release",
Expand Down Expand Up @@ -43,23 +43,27 @@
"lerna": "3.22.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "8.8.0",
"@typescript-eslint/parser": "8.8.0",
"@tsed/monorepo-utils": "1.11.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"cross-env": "7.0.2",
"eslint": "^7.10.0",
"eslint-config-prettier": "6.12.0",
"eslint-plugin-prettier": "3.1.4",
"eslint-plugin-mocha": "8.0.0",
"eslint": "9.13.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-vitest": "0.5.4",
"proxyquire": "2.1.3",
"husky": "4.3.0",
"lint-staged": "10.4.0",
"mocha": "8.1.3",
"nyc": "15.1.0",
"prettier": "2.1.2",
"prettier": "3.3.3",
"semantic-release": "17.2.3",
"sinon": "9.0.3",
"sinon-chai": "3.5.0"
"sinon-chai": "3.5.0",
"typescript": "5.6.3"
},
"workspaces": {
"packages": [
Expand Down
3 changes: 2 additions & 1 deletion packages/ts-doc/src/highlight/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use strict";

const {context} = require("../context");
const KEYWORDS = /(\benum\b|\bstatic\b|\bclass\b|\binterface\b|\bprivate\b|\bpublic\b|\bconst\b|\blet\b|\bprotected\b|\bimplements\b|\bconstructor\b|\breadonly\b|\babstract\b|\bimport\b|\bexport\b|\bas\b|\bfrom\b|\bextends\b)/g;
const KEYWORDS =
/(\benum\b|\bstatic\b|\bclass\b|\binterface\b|\bprivate\b|\bpublic\b|\bconst\b|\blet\b|\bprotected\b|\bimplements\b|\bconstructor\b|\breadonly\b|\babstract\b|\bimport\b|\bexport\b|\bas\b|\bfrom\b|\bextends\b)/g;
const TYPES = /(\bany\b|\bstring\b|\bboolean\b|\bnumber\b|\bDate\b|\bvoid\b)/g;
const SEPARATOR = /(:|;|,|\(|\)|{|}|\[|\]| = )/g;

Expand Down
34 changes: 19 additions & 15 deletions packages/ts-doc/src/models/DocFile.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const {context} = require("../context");
const path = require("path");
const fs = require("fs");
const fs = require("fs/promises");
const fsSync = require("fs");
const normalizePath = require("normalize-path");
const readPkgUp = require("read-pkg-up");
const {logger} = require("../context/context");
const mapExported = new Map();

class DocFile {
Expand All @@ -13,7 +15,7 @@ class DocFile {
constructor(file) {
this.file = normalizePath(file);
this.symbols = new Map();
this.contents = fs.readFileSync(file).toString();
this.contents = fsSync.readFileSync(file).toString();
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider implementing lazy loading for file contents.

Reading file contents synchronously in the constructor could block execution for large files. Consider implementing lazy loading where contents are read only when needed:

 constructor(file) {
   this.file = normalizePath(file);
   this.symbols = new Map();
-  this.contents = fsSync.readFileSync(file).toString();
+  this._contents = null;
 }
+
+get contents() {
+  if (!this._contents) {
+    this._contents = fsSync.readFileSync(this.file).toString();
+  }
+  return this._contents;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.contents = fsSync.readFileSync(file).toString();
constructor(file) {
this.file = normalizePath(file);
this.symbols = new Map();
this._contents = null;
}
get contents() {
if (!this._contents) {
this._contents = fsSync.readFileSync(this.file).toString();
}
return this._contents;
}

}

get path() {
Expand Down Expand Up @@ -50,24 +52,26 @@ class DocFile {
};
}

requireModule() {
async importModule() {
const {modulePath} = this.module;
let file = path.join(modulePath, "index.js");
try {
if (fsSync.existsSync(path.join(modulePath, "package.json"))) {
const pkg = JSON.parse(await fs.readFile(path.join(modulePath, "package.json"), {encoding: "utf-8"}));
file = path.join(modulePath, pkg.main);
}
Comment on lines +59 to +62
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace sync existence check with async implementation.

The mix of existsSync with async readFile creates an inconsistent pattern. Consider using fs.access or catching ENOENT from readFile.

-if (fsSync.existsSync(path.join(modulePath, "package.json"))) {
-  const pkg = JSON.parse(await fs.readFile(path.join(modulePath, "package.json"), {encoding: "utf-8"}));
-  file = path.join(modulePath, pkg.main);
+try {
+  const pkg = JSON.parse(await fs.readFile(path.join(modulePath, "package.json"), {encoding: "utf-8"}));
+  file = path.join(modulePath, pkg.main);
+} catch (error) {
+  if (error.code !== 'ENOENT') {
+    throw error;
+  }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (fsSync.existsSync(path.join(modulePath, "package.json"))) {
const pkg = JSON.parse(await fs.readFile(path.join(modulePath, "package.json"), {encoding: "utf-8"}));
file = path.join(modulePath, pkg.main);
}
try {
const pkg = JSON.parse(await fs.readFile(path.join(modulePath, "package.json"), {encoding: "utf-8"}));
file = path.join(modulePath, pkg.main);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}


if (fs.existsSync(path.join(modulePath, "package.json"))) {
const pkg = require(path.join(modulePath, "package.json"));
file = path.join(modulePath, pkg.main);
}

if (mapExported.has(file)) {
return mapExported.get(file);
}
if (mapExported.has(file)) {
return mapExported.get(file);
}

if (fs.existsSync(file)) {
mapExported.set(file, require(file));
return mapExported.get(file);
if (fsSync.existsSync(file)) {
mapExported.set(file, await import(file));
return mapExported.get(file);
}
} catch (er) {
logger.error("Fail to import module", {file, modulePath});
}
Comment on lines +72 to 74
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance error handling with specific error types.

The current error handling swallows all errors and only logs them. Consider:

  1. Creating specific error types
  2. Providing more context in error messages
  3. Allowing error propagation for critical failures
-  } catch (er) {
-    logger.error("Fail to import module", {file, modulePath});
+  } catch (error) {
+    logger.error("Failed to import module", {
+      file,
+      modulePath,
+      errorCode: error.code,
+      errorMessage: error.message
+    });
+    if (error.code !== 'MODULE_NOT_FOUND') {
+      throw new Error(`Failed to import module at ${file}: ${error.message}`);
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (er) {
logger.error("Fail to import module", {file, modulePath});
}
} catch (error) {
logger.error("Failed to import module", {
file,
modulePath,
errorCode: error.code,
errorMessage: error.message
});
if (error.code !== 'MODULE_NOT_FOUND') {
throw new Error(`Failed to import module at ${file}: ${error.message}`);
}
}

Comment on lines +55 to 74
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Based on the gathered information, I can now provide the final response:

ESM changes require additional configuration before implementation

The codebase currently uses CommonJS (require/module.exports) throughout, and there's no ESM configuration in package.json. Switching to import statements without proper setup will cause compatibility issues:

  • packages/ts-doc/src/scan/scan.js and packages/ts-doc/src/models/DocFile.spec.js use CommonJS requires
  • packages/ts-doc/src/models/DocFile.js exports using CommonJS
  • Package.json lacks "type": "module" field and ESM-related configurations
🔗 Analysis chain

Verify the impact of ESM changes across the codebase.

The switch from require to import might affect other parts of the codebase that depend on this module.


Let me gather more information about the ESM compatibility by checking the package.json and any other ESM-related configurations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for requires of this module
rg "require.*DocFile" -A 2

# Search for potential CommonJS interop issues
rg "module\.exports.*=.*DocFile" -A 2

Length of output: 576


Script:

#!/bin/bash
# Check package.json for type and exports configuration
cat packages/ts-doc/package.json

# Look for any ESM-specific configurations or imports
rg "type.*=.*module" packages/ts-doc/
rg "import.*from" packages/ts-doc/src/

Length of output: 2515


return undefined;
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ts-doc/src/models/DocSymbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class DocSymbol {
});
}

setDocFile(docFile) {
async setDocFile(docFile) {
this.docFile = docFile;

if (this.relativePath.match("decorators") && this.symbolType === "function") {
Expand All @@ -178,7 +178,7 @@ class DocSymbol {
if (this.symbolType !== "interface") {
this.private = true;

const exported = this.docFile.requireModule();
const exported = await this.docFile.importModule();

if (exported) {
const symbolPrivate = exported[this.symbolName.trim()];
Expand Down
6 changes: 3 additions & 3 deletions packages/ts-doc/src/models/DocSymbol.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const context = require("../context/context");
const {expect} = require("../test/tools");

describe("DocSymbol", () => {
before(() => {
before(async () => {
context.github = "https://github.com/repo";
context.version = "1.0.0";

Expand All @@ -26,7 +26,7 @@ describe("DocSymbol", () => {

this.docSymbol = new DocSymbol();
this.docSymbol.symbolName = "SymbolName";
this.docSymbol.setDocFile({
await this.docSymbol.setDocFile({
file: path.join(process.cwd(), "/packages/common/di/lib/file.d.ts"),
path: path.join(process.cwd(), "/packages/common/di/lib/file.ts"),
srcPath: path.join(process.cwd(), "/packages/common/di/src/file.ts"),
Expand All @@ -39,7 +39,7 @@ describe("DocSymbol", () => {
pkgName: "common",
subPkgName: "di"
},
requireModule() {
importModule() {
return {};
}
});
Expand Down
17 changes: 11 additions & 6 deletions packages/ts-doc/src/parsers/DocParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {DocSymbolParser} = require("./DocSymbolParser");
const {sumBracket} = require("./sum-bracket");

const {stripsTags} = require("../utils/strips");
const {logger} = require("../context/context");

const EXPORT_PATTERN = /^export /;

Expand Down Expand Up @@ -33,14 +34,18 @@ class DocParser {
this.contents = contents;
}

static parse(docFile) {
static async parse(docFile) {
const {symbols} = new DocParser(docFile.contents).parse();

symbols.forEach((symbol) => {
symbol.setDocFile(docFile);
symbol = context.symbols.push(symbol);
docFile.symbols.set(symbol.symbolName, symbol);
});
for (const [, symbol] of symbols) {
try {
await symbol.setDocFile(docFile);
const newSymbol = context.symbols.push(symbol);
docFile.symbols.set(newSymbol.symbolName, newSymbol);
} catch (er) {
logger.error("Fail to process symbol", {symbol, error: er});
}
}

return docFile.symbols;
}
Expand Down
11 changes: 7 additions & 4 deletions packages/ts-doc/src/scan/scan.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,24 @@ module.exports = {
*
* @param patterns
*/
scanFiles(patterns) {
async scanFiles(patterns) {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider converting other scanning methods to async.

While the async conversion of scanFiles is correct, consider converting scanComponents and scanTemplate methods to async as well for consistency, since they also use globby.

Apply this pattern to other methods:

- scanComponents(directory) {
+ async scanComponents(directory) {
   context.logger("Scan components '" + chalk.cyan(directory) + "'");
-  const files = globby.sync(path.join(directory, "**/*.ejs"));
+  const files = await globby(path.join(directory, "**/*.ejs"));

- scanTemplate(templatePattern) {
+ async scanTemplate(templatePattern) {
   context.logger("Scan template directory '" + chalk.cyan(templatePattern) + "'");
-  let files = globby.sync(templatePattern);
+  let files = await globby(templatePattern);

Committable suggestion was skipped due to low confidence.

context.logger("Scan folders '" + chalk.cyan(JSON.stringify(patterns)) + "'");

let symbolsSize = 0;
const files = await globby(patterns);

globby.sync(patterns).forEach((file) => {
for (const file of files) {
try {
DocParser.parse(new DocFile(file)).forEach((symbol) => {
const symbols = await DocParser.parse(new DocFile(file));

symbols.forEach((symbol) => {
context.logger(`Scanned symbol '${chalk.cyan(symbol.symbolName)}'`);
symbolsSize++;
});
} catch (er) {
context.logger.error(chalk.red(er), er.stack);
}
});
}
Comment on lines +58 to +69
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling and reporting.

While the async/await conversion is correct, the error handling could be improved to:

  1. Track failed files separately
  2. Provide more accurate final statistics
+ let failedFiles = 0;
  for (const file of files) {
    try {
      const symbols = await DocParser.parse(new DocFile(file));
      symbols.forEach((symbol) => {
        context.logger(`Scanned symbol '${chalk.cyan(symbol.symbolName)}'`);
        symbolsSize++;
      });
    } catch (er) {
      context.logger.error(chalk.red(er), er.stack);
+     context.logger.error(`Failed to parse file: ${chalk.red(file)}`);
+     failedFiles++;
    }
  }

- context.logger(`${chalk.green(symbolsSize)} scanned symbols`);
+ context.logger(
+   `${chalk.green(symbolsSize)} scanned symbols, ` +
+   `${chalk.red(failedFiles)} files failed`
+ );

Committable suggestion was skipped due to low confidence.


context.logger(`${chalk.green(symbolsSize)} scanned symbols`);
}
Expand Down
Loading