docs-util: created docblock-generator tool (#6096)
This commit is contained in:
@@ -24,11 +24,12 @@ packages/*
|
|||||||
!packages/orchestration
|
!packages/orchestration
|
||||||
!packages/workflows-sdk
|
!packages/workflows-sdk
|
||||||
!packages/core-flows
|
!packages/core-flows
|
||||||
|
!packages/types
|
||||||
|
!packages/medusa-react
|
||||||
!packages/workflow-engine-redis
|
!packages/workflow-engine-redis
|
||||||
!packages/workflow-engine-inmemory
|
!packages/workflow-engine-inmemory
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**/models/*
|
**/models/*
|
||||||
**/scripts/*
|
**/scripts/*
|
||||||
**/dist/*
|
**/dist/*
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ module.exports = {
|
|||||||
"./packages/orchestration/tsconfig.json",
|
"./packages/orchestration/tsconfig.json",
|
||||||
"./packages/workflows-sdk/tsconfig.spec.json",
|
"./packages/workflows-sdk/tsconfig.spec.json",
|
||||||
"./packages/core-flows/tsconfig.spec.json",
|
"./packages/core-flows/tsconfig.spec.json",
|
||||||
|
"./packages/types/tsconfig.json",
|
||||||
"./packages/workflow-engine-redis/tsconfig.spec.json",
|
"./packages/workflow-engine-redis/tsconfig.spec.json",
|
||||||
"./packages/workflow-engine-inmemory/tsconfig.spec.json",
|
"./packages/workflow-engine-inmemory/tsconfig.spec.json",
|
||||||
],
|
],
|
||||||
|
|||||||
40
.github/workflows/release.yml
vendored
40
.github/workflows/release.yml
vendored
@@ -38,3 +38,43 @@ jobs:
|
|||||||
uses: changesets/action@v1
|
uses: changesets/action@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tsdoc-pr:
|
||||||
|
name: Generated TSDoc PRs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Node.js 16
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: yarn
|
||||||
|
|
||||||
|
- name: Build packages
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: Install docs-util Dependencies
|
||||||
|
run: yarn
|
||||||
|
working-directory: docs-util
|
||||||
|
|
||||||
|
- name: Build packages
|
||||||
|
run: yarn build
|
||||||
|
working-directory: docs-util
|
||||||
|
|
||||||
|
- name: Run docblock generator
|
||||||
|
run: "yarn start run:commit ${{ github.sha }}"
|
||||||
|
working-directory: docs-util/packages/docblock-generator
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v5
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
title: "Generated TSDocs"
|
||||||
|
body: "This PR holds all generated TSDocs for the upcoming release."
|
||||||
|
branch: "chore/generate-tsdocs"
|
||||||
|
team-reviewers: "@medusajs/docs"
|
||||||
|
add-paths: packages/**
|
||||||
1
docs-util/packages/docblock-generator/.env.sample
Normal file
1
docs-util/packages/docblock-generator/.env.sample
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MONOREPO_ROOT_PATH=/Users/medusa/medusa
|
||||||
38
docs-util/packages/docblock-generator/README.md
Normal file
38
docs-util/packages/docblock-generator/README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# docblock-generator
|
||||||
|
|
||||||
|
A CLI tool that can be used to generate TSDoc docblocks for TypeScript/JavaScript files under the `packages` directory of the main monorepo.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. Run the `yarn` command to install dependencies.
|
||||||
|
2. Copy the `.env.sample` to `.env` and change the `MONOREPO_ROOT_PATH` variable to the absolute path to the monorepo root.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Generate for a specific file
|
||||||
|
|
||||||
|
Run the following command to run the tool for a specific file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn start run /absolute/path/to/file.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate for git-changed files
|
||||||
|
|
||||||
|
Run the following command to run the tool for applicable git file changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn start run:changes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate for a specific commit
|
||||||
|
|
||||||
|
Run the following command to run the tool for a commit SHA hash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn start run:commit <commit-sha>
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `<commit-sha>` is the SHA of the commit. For example, `e28fa7fbdf45c5b1fa19848db731132a0bf1757d`.
|
||||||
31
docs-util/packages/docblock-generator/package.json
Normal file
31
docs-util/packages/docblock-generator/package.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "docblock-generator",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"start": "ts-node src/index.ts",
|
||||||
|
"build": "tsc",
|
||||||
|
"watch": "tsc --watch",
|
||||||
|
"prepublishOnly": "cross-env NODE_ENV=production tsc --build"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"exports": "./dist/index.js",
|
||||||
|
"bin": {
|
||||||
|
"workflow-diagrams-generator": "dist/index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/core": "^5.0.2",
|
||||||
|
"commander": "^11.1.0",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"minimatch": "^9.0.3",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "5.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.9.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/* eslint-disable no-case-declarations */
|
||||||
|
import ts from "typescript"
|
||||||
|
import Formatter from "./formatter.js"
|
||||||
|
import KindsRegistry from "./kinds/registry.js"
|
||||||
|
import nodeHasComments from "../utils/node-has-comments.js"
|
||||||
|
|
||||||
|
export type Options = {
|
||||||
|
paths: string[]
|
||||||
|
dryRun?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class used to generate docblock for one or multiple file paths.
|
||||||
|
*/
|
||||||
|
class DocblockGenerator {
|
||||||
|
protected options: Options
|
||||||
|
protected program?: ts.Program
|
||||||
|
protected checker?: ts.TypeChecker
|
||||||
|
protected formatter: Formatter
|
||||||
|
protected kindsRegistry?: KindsRegistry
|
||||||
|
|
||||||
|
constructor(options: Options) {
|
||||||
|
this.options = options
|
||||||
|
this.formatter = new Formatter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the docblock for the paths specified in the {@link options} class property.
|
||||||
|
*/
|
||||||
|
async run() {
|
||||||
|
this.program = ts.createProgram(this.options.paths, {})
|
||||||
|
|
||||||
|
this.checker = this.program.getTypeChecker()
|
||||||
|
|
||||||
|
this.kindsRegistry = new KindsRegistry(this.checker)
|
||||||
|
|
||||||
|
const printer = ts.createPrinter({
|
||||||
|
removeComments: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
this.program.getSourceFiles().map(async (file) => {
|
||||||
|
// Ignore .d.ts files
|
||||||
|
if (file.isDeclarationFile || !this.isFileIncluded(file.fileName)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Generating for ${file.fileName}...`)
|
||||||
|
|
||||||
|
let fileContent = file.getFullText()
|
||||||
|
let fileComments: string = ""
|
||||||
|
|
||||||
|
const documentChild = (node: ts.Node, topLevel = false) => {
|
||||||
|
const isSourceFile = ts.isSourceFile(node)
|
||||||
|
const origNodeText = node.getFullText().trim()
|
||||||
|
const nodeKindGenerator = this.kindsRegistry?.getKindGenerator(node)
|
||||||
|
let docComment: string | undefined
|
||||||
|
|
||||||
|
if (nodeKindGenerator && this.canDocumentNode(node)) {
|
||||||
|
docComment = nodeKindGenerator.getDocBlock(node)
|
||||||
|
if (docComment.length) {
|
||||||
|
if (isSourceFile) {
|
||||||
|
fileComments = docComment
|
||||||
|
} else {
|
||||||
|
ts.addSyntheticLeadingComment(
|
||||||
|
node,
|
||||||
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
||||||
|
docComment,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.forEachChild(node, (childNode) =>
|
||||||
|
documentChild(childNode, isSourceFile)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isSourceFile && topLevel) {
|
||||||
|
const newNodeText = printer.printNode(
|
||||||
|
ts.EmitHint.Unspecified,
|
||||||
|
node,
|
||||||
|
file
|
||||||
|
)
|
||||||
|
|
||||||
|
if (newNodeText !== origNodeText) {
|
||||||
|
fileContent = fileContent.replace(origNodeText, newNodeText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
documentChild(file, true)
|
||||||
|
|
||||||
|
if (!this.options.dryRun) {
|
||||||
|
ts.sys.writeFile(
|
||||||
|
file.fileName,
|
||||||
|
this.formatter.addCommentsToSourceFile(
|
||||||
|
fileComments,
|
||||||
|
await this.formatter.formatStr(fileContent, file.fileName)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Finished generating docblock for ${file.fileName}.`)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a file is included in the specified files.
|
||||||
|
*
|
||||||
|
* @param {string} fileName - The file to check for.
|
||||||
|
* @returns {boolean} Whether the file can have docblocks generated for it.
|
||||||
|
*/
|
||||||
|
isFileIncluded(fileName: string): boolean {
|
||||||
|
return this.options.paths.some((path) => path.includes(fileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node can be documented.
|
||||||
|
*
|
||||||
|
* @privateRemark
|
||||||
|
* I'm leaving this method in case other conditions arise for a node to be documented.
|
||||||
|
* Otherwise, we can directly use the {@link nodeHasComments} function.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check for.
|
||||||
|
* @returns {boolean} Whether the node can be documented.
|
||||||
|
*/
|
||||||
|
canDocumentNode(node: ts.Node): boolean {
|
||||||
|
// check if node already has docblock
|
||||||
|
return !nodeHasComments(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the generator's properties for new usage.
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
this.program = undefined
|
||||||
|
this.checker = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DocblockGenerator
|
||||||
238
docs-util/packages/docblock-generator/src/classes/formatter.ts
Normal file
238
docs-util/packages/docblock-generator/src/classes/formatter.ts
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
import getMonorepoRoot from "../utils/get-monorepo-root.js"
|
||||||
|
import { ESLint, Linter } from "eslint"
|
||||||
|
import path from "path"
|
||||||
|
import dirname from "../utils/dirname.js"
|
||||||
|
import { minimatch } from "minimatch"
|
||||||
|
import { existsSync } from "fs"
|
||||||
|
import getRelativePaths from "../utils/get-relative-paths.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class used to apply formatting to files using ESLint and other formatting options.
|
||||||
|
*/
|
||||||
|
class Formatter {
|
||||||
|
protected cwd: string
|
||||||
|
protected eslintConfig?: Linter.Config
|
||||||
|
protected generalESLintConfig?: Linter.ConfigOverride<Linter.RulesRecord>
|
||||||
|
protected configForFile: Map<
|
||||||
|
string,
|
||||||
|
Linter.ConfigOverride<Linter.RulesRecord>
|
||||||
|
>
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.cwd = getMonorepoRoot()
|
||||||
|
this.configForFile = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new lines before and after a comment if it's preceeded/followed immediately by a word (not by an empty line).
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to format.
|
||||||
|
* @returns {string} The returned formatted content.
|
||||||
|
*/
|
||||||
|
normalizeCommentNewLine(content: string): string {
|
||||||
|
return content
|
||||||
|
.replaceAll(/(.)\n(\s*)\/\*\*/g, "$1\n\n$2/**")
|
||||||
|
.replaceAll(/\*\/\s*(.)/g, "*/\n$1")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes an ESLint overrides configuration object. If a file name is specified, the configuration are normalized to
|
||||||
|
* include the `tsconfig` related to the file. If a file name isn't specified, the tsconfig file path names
|
||||||
|
* in the `parserConfig.project` array are normalized to have a full relative path (as that is required by ESLint).
|
||||||
|
*
|
||||||
|
* @param {Linter.ConfigOverride<Linter.RulesRecord>} config - The original configuration object.
|
||||||
|
* @param {string} fileName - The file name that
|
||||||
|
* @returns {Linter.ConfigOverride<Linter.RulesRecord>} The normalized and cloned configuration object.
|
||||||
|
*/
|
||||||
|
normalizeOverridesConfigObject(
|
||||||
|
config: Linter.ConfigOverride<Linter.RulesRecord>,
|
||||||
|
fileName?: string
|
||||||
|
): Linter.ConfigOverride<Linter.RulesRecord> {
|
||||||
|
// clone config
|
||||||
|
const newConfig = structuredClone(config)
|
||||||
|
if (!newConfig.parserOptions) {
|
||||||
|
return newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName) {
|
||||||
|
const packagePattern = /^(?<packagePath>.*\/packages\/[^/]*).*$/
|
||||||
|
// try to manually set the project of the parser options
|
||||||
|
const matchFilePackage = packagePattern.exec(fileName)
|
||||||
|
|
||||||
|
if (matchFilePackage?.groups?.packagePath) {
|
||||||
|
const tsConfigPath = path.join(
|
||||||
|
matchFilePackage.groups.packagePath,
|
||||||
|
"tsconfig.json"
|
||||||
|
)
|
||||||
|
const tsConfigSpecPath = path.join(
|
||||||
|
matchFilePackage.groups.packagePath,
|
||||||
|
"tsconfig.spec.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
newConfig.parserOptions.project = [
|
||||||
|
existsSync(tsConfigSpecPath)
|
||||||
|
? tsConfigSpecPath
|
||||||
|
: existsSync(tsConfigPath)
|
||||||
|
? tsConfigPath
|
||||||
|
: [
|
||||||
|
...getRelativePaths(
|
||||||
|
newConfig.parserOptions.project || [],
|
||||||
|
this.cwd
|
||||||
|
),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (newConfig.parserOptions.project?.length) {
|
||||||
|
// fix parser projects paths to be relative to this script
|
||||||
|
newConfig.parserOptions.project = getRelativePaths(
|
||||||
|
newConfig.parserOptions.project as string[],
|
||||||
|
this.cwd
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the general ESLint configuration and sets it to the `eslintConfig` class property, if it's not already set.
|
||||||
|
* It also tries to set the `generalESLintConfig` class property to the override configuration in the `eslintConfig`
|
||||||
|
* whose `files` array includes `*.ts`.
|
||||||
|
*/
|
||||||
|
async getESLintConfig() {
|
||||||
|
if (this.eslintConfig) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eslintConfig = (
|
||||||
|
await import(
|
||||||
|
path.relative(dirname(), path.join(this.cwd, ".eslintrc.js"))
|
||||||
|
)
|
||||||
|
).default as Linter.Config
|
||||||
|
|
||||||
|
this.generalESLintConfig = this.eslintConfig!.overrides?.find((item) =>
|
||||||
|
item.files.includes("*.ts")
|
||||||
|
)
|
||||||
|
|
||||||
|
if (this.generalESLintConfig) {
|
||||||
|
this.generalESLintConfig = this.normalizeOverridesConfigObject(
|
||||||
|
this.generalESLintConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the normalized ESLint overrides configuration for a specific file.
|
||||||
|
*
|
||||||
|
* @param {string} filePath - The file's path.
|
||||||
|
* @returns {Promise<Linter.ConfigOverride<Linter.RulesRecord> | undefined>} The normalized configuration object or `undefined` if not found.
|
||||||
|
*/
|
||||||
|
async getESLintOverridesConfigForFile(
|
||||||
|
filePath: string
|
||||||
|
): Promise<Linter.ConfigOverride<Linter.RulesRecord> | undefined> {
|
||||||
|
await this.getESLintConfig()
|
||||||
|
|
||||||
|
if (this.configForFile.has(filePath)) {
|
||||||
|
return this.configForFile.get(filePath)!
|
||||||
|
}
|
||||||
|
|
||||||
|
let relevantConfig = this.eslintConfig!.overrides?.find((item) => {
|
||||||
|
if (typeof item.files === "string") {
|
||||||
|
return minimatch(filePath, item.files)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.files.some((file) => minimatch(filePath, file))
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!relevantConfig && !this.generalESLintConfig) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
relevantConfig = this.normalizeOverridesConfigObject(
|
||||||
|
structuredClone(relevantConfig || this.generalESLintConfig!),
|
||||||
|
filePath
|
||||||
|
)
|
||||||
|
|
||||||
|
relevantConfig!.files = [path.relative(this.cwd, filePath)]
|
||||||
|
|
||||||
|
this.configForFile.set(filePath, relevantConfig)
|
||||||
|
|
||||||
|
return relevantConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a string with ESLint.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to format.
|
||||||
|
* @param {string} fileName - The path to the file that the content belongs to.
|
||||||
|
* @returns {Promise<string>} The formatted content.
|
||||||
|
*/
|
||||||
|
async formatStrWithEslint(
|
||||||
|
content: string,
|
||||||
|
fileName: string
|
||||||
|
): Promise<string> {
|
||||||
|
const relevantConfig = await this.getESLintOverridesConfigForFile(fileName)
|
||||||
|
|
||||||
|
const eslint = new ESLint({
|
||||||
|
overrideConfig: {
|
||||||
|
...this.eslintConfig,
|
||||||
|
overrides: relevantConfig ? [relevantConfig] : undefined,
|
||||||
|
},
|
||||||
|
cwd: this.cwd,
|
||||||
|
resolvePluginsRelativeTo: this.cwd,
|
||||||
|
fix: true,
|
||||||
|
ignore: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
let newContent = content
|
||||||
|
const result = await eslint.lintText(content, {
|
||||||
|
filePath: fileName,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.length) {
|
||||||
|
newContent = result[0].output || newContent
|
||||||
|
}
|
||||||
|
|
||||||
|
return newContent
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies all formatting types to a string.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to format.
|
||||||
|
* @param {string} fileName - The path to the file that holds the content.
|
||||||
|
* @returns {Promise<string>} The formatted content.
|
||||||
|
*/
|
||||||
|
async formatStr(content: string, fileName: string): Promise<string> {
|
||||||
|
const newContent = await this.formatStrWithEslint(content, fileName)
|
||||||
|
|
||||||
|
let normalizedContent = this.normalizeCommentNewLine(newContent)
|
||||||
|
|
||||||
|
if (normalizedContent !== newContent) {
|
||||||
|
/**
|
||||||
|
* Since adding the new lines after comments as done in {@link normalizeCommentNewLine} method may lead to linting errors,
|
||||||
|
* we have to rerun the {@link formatStrWithEslint}. It's not possible to run {@link normalizeCommentNewLine} the first time
|
||||||
|
* and provide the expected result.
|
||||||
|
*/
|
||||||
|
normalizedContent = await this.formatStrWithEslint(
|
||||||
|
normalizedContent,
|
||||||
|
fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedContent
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds comments of a source file to the top of the file's content. It should have additional extra line after the comment.
|
||||||
|
* If the comment's length is 0, the `content` is returned as is.
|
||||||
|
*
|
||||||
|
* @param {string} comment - The comments of the source file.
|
||||||
|
* @param {string} content - The source file's comments.
|
||||||
|
* @returns {string} The full content with the comments.
|
||||||
|
*/
|
||||||
|
addCommentsToSourceFile(comment: string, content: string): string {
|
||||||
|
return comment.length ? `/**\n ${comment}*/\n\n${content}` : content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Formatter
|
||||||
@@ -0,0 +1,503 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import {
|
||||||
|
DOCBLOCK_START,
|
||||||
|
DOCBLOCK_END_LINE,
|
||||||
|
DOCBLOCK_DOUBLE_LINES,
|
||||||
|
DOCBLOCK_NEW_LINE,
|
||||||
|
} from "../../constants.js"
|
||||||
|
import getSymbol from "../../utils/get-symbol.js"
|
||||||
|
import KnowledgeBaseFactory, {
|
||||||
|
RetrieveOptions,
|
||||||
|
} from "../knowledge-base-factory.js"
|
||||||
|
import {
|
||||||
|
getCustomNamespaceTag,
|
||||||
|
shouldHaveCustomNamespace,
|
||||||
|
} from "../../utils/medusa-react-utils.js"
|
||||||
|
import {
|
||||||
|
camelToWords,
|
||||||
|
capitalize,
|
||||||
|
normalizeName,
|
||||||
|
} from "../../utils/str-formatting.js"
|
||||||
|
|
||||||
|
export type GeneratorOptions = {
|
||||||
|
checker: ts.TypeChecker
|
||||||
|
kinds?: ts.SyntaxKind[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetDocBlockOptions = {
|
||||||
|
addEnd?: boolean
|
||||||
|
summaryPrefix?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommonDocsOptions = {
|
||||||
|
addDefaultSummary?: boolean
|
||||||
|
prefixWithLineBreaks?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to generate docblocks for basic kinds. It can be
|
||||||
|
* extended for kinds requiring more elaborate TSDocs.
|
||||||
|
*/
|
||||||
|
class DefaultKindGenerator<T extends ts.Node = ts.Node> {
|
||||||
|
static DEFAULT_ALLOWED_NODE_KINDS = [
|
||||||
|
ts.SyntaxKind.SourceFile,
|
||||||
|
ts.SyntaxKind.ClassDeclaration,
|
||||||
|
ts.SyntaxKind.EnumDeclaration,
|
||||||
|
ts.SyntaxKind.EnumMember,
|
||||||
|
ts.SyntaxKind.ModuleDeclaration,
|
||||||
|
ts.SyntaxKind.PropertyDeclaration,
|
||||||
|
ts.SyntaxKind.InterfaceDeclaration,
|
||||||
|
ts.SyntaxKind.TypeAliasDeclaration,
|
||||||
|
ts.SyntaxKind.PropertySignature,
|
||||||
|
]
|
||||||
|
protected allowedKinds: ts.SyntaxKind[]
|
||||||
|
protected checker: ts.TypeChecker
|
||||||
|
protected defaultSummary = "{summary}"
|
||||||
|
protected knowledgeBaseFactory: KnowledgeBaseFactory
|
||||||
|
|
||||||
|
constructor({ checker, kinds }: GeneratorOptions) {
|
||||||
|
this.allowedKinds = kinds || DefaultKindGenerator.DEFAULT_ALLOWED_NODE_KINDS
|
||||||
|
this.checker = checker
|
||||||
|
this.knowledgeBaseFactory = new KnowledgeBaseFactory()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the kinds that are handled by this generator.
|
||||||
|
*/
|
||||||
|
getAllowedKinds(): ts.SyntaxKind[] {
|
||||||
|
return this.allowedKinds
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether this generator can be used for a node based on the node's kind.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check for.
|
||||||
|
* @returns {boolean} Whether this generator can be used with the specified node.
|
||||||
|
*/
|
||||||
|
isAllowed(node: ts.Node): node is T {
|
||||||
|
return this.allowedKinds.includes(node.kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the doc block for the passed node.
|
||||||
|
*
|
||||||
|
* @param {T | ts.Node} node - The node to retrieve the docblock for.
|
||||||
|
* @param {GetDocBlockOptions} options - Options useful for children classes of this class to specify the formatting of the docblock.
|
||||||
|
* @returns {string} The node's docblock.
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
getDocBlock(
|
||||||
|
node: T | ts.Node,
|
||||||
|
options: GetDocBlockOptions = { addEnd: true }
|
||||||
|
): string {
|
||||||
|
let str = DOCBLOCK_START
|
||||||
|
const summary = this.getNodeSummary({ node })
|
||||||
|
|
||||||
|
switch (node.kind) {
|
||||||
|
case ts.SyntaxKind.EnumDeclaration:
|
||||||
|
str += `@enum${DOCBLOCK_DOUBLE_LINES}${summary}`
|
||||||
|
break
|
||||||
|
case ts.SyntaxKind.TypeAliasDeclaration:
|
||||||
|
str += `@interface${DOCBLOCK_DOUBLE_LINES}${summary}`
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
str += summary
|
||||||
|
}
|
||||||
|
|
||||||
|
str += this.getCommonDocs(node, {
|
||||||
|
prefixWithLineBreaks: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return `${str}${options.addEnd ? DOCBLOCK_END_LINE : ""}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the summary comment of a node. It gives precedense to the node's symbol if it's provided/retrieved and if it's available using the {@link getSymbolDocBlock}.
|
||||||
|
* Otherwise, it retrieves the comments of the type using the {@link getTypeDocBlock}
|
||||||
|
* @returns {string} The summary comment.
|
||||||
|
*/
|
||||||
|
getNodeSummary({
|
||||||
|
node,
|
||||||
|
symbol,
|
||||||
|
nodeType,
|
||||||
|
}: {
|
||||||
|
/**
|
||||||
|
* The node to retrieve the summary comment for.
|
||||||
|
*/
|
||||||
|
node: T | ts.Node
|
||||||
|
/**
|
||||||
|
* Optionally provide the node's symbol. If not provided, the
|
||||||
|
* method will try to retrieve it.
|
||||||
|
*/
|
||||||
|
symbol?: ts.Symbol
|
||||||
|
/**
|
||||||
|
* Optionally provide the node's type. If not provided, the method
|
||||||
|
* will try to retrieve it.
|
||||||
|
*/
|
||||||
|
nodeType?: ts.Type
|
||||||
|
}): string {
|
||||||
|
const knowledgeBaseOptions = this.getKnowledgeOptions(node)
|
||||||
|
if (!nodeType) {
|
||||||
|
nodeType =
|
||||||
|
"type" in node && node.type && ts.isTypeNode(node.type as ts.Node)
|
||||||
|
? this.checker.getTypeFromTypeNode(node.type as ts.TypeNode)
|
||||||
|
: symbol
|
||||||
|
? this.checker.getTypeOfSymbolAtLocation(symbol, node)
|
||||||
|
: this.checker.getTypeAtLocation(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!symbol) {
|
||||||
|
symbol = getSymbol(node, this.checker)
|
||||||
|
}
|
||||||
|
|
||||||
|
let summary = ""
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
summary = this.getSymbolDocBlock(symbol, knowledgeBaseOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!summary.length) {
|
||||||
|
summary = this.getTypeDocBlock(nodeType, knowledgeBaseOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary.length > 0 ? summary : this.defaultSummary
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the summary comment of a type. It tries to retrieve from the alias symbol, type arguments, or {@link KnowledgeBaseFactory}.
|
||||||
|
* If no summary comments are found, the {@link defaultSummary} is used.
|
||||||
|
*
|
||||||
|
* @param {ts.Type} nodeType - The type of a node.
|
||||||
|
* @returns {string} The summary comment.
|
||||||
|
*/
|
||||||
|
private getTypeDocBlock(
|
||||||
|
nodeType: ts.Type,
|
||||||
|
knowledgeBaseOptions?: Partial<RetrieveOptions>
|
||||||
|
): string {
|
||||||
|
if (nodeType.aliasSymbol || nodeType.symbol) {
|
||||||
|
const symbolDoc = this.getSymbolDocBlock(
|
||||||
|
nodeType.aliasSymbol || nodeType.symbol
|
||||||
|
)
|
||||||
|
|
||||||
|
if (symbolDoc.length) {
|
||||||
|
return symbolDoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeArguments = this.checker.getTypeArguments(
|
||||||
|
nodeType as ts.TypeReference
|
||||||
|
)
|
||||||
|
|
||||||
|
if (typeArguments.length) {
|
||||||
|
// take only the first type argument to account
|
||||||
|
const typeArgumentDoc = this.getTypeDocBlock(typeArguments[0])
|
||||||
|
|
||||||
|
if (!typeArgumentDoc.length) {
|
||||||
|
const tryKnowledgeSummary = this.knowledgeBaseFactory.tryToGetSummary({
|
||||||
|
...knowledgeBaseOptions,
|
||||||
|
str: this.checker.typeToString(nodeType),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (tryKnowledgeSummary?.length) {
|
||||||
|
return tryKnowledgeSummary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.checker.isArrayType(nodeType)) {
|
||||||
|
return typeArgumentDoc
|
||||||
|
}
|
||||||
|
|
||||||
|
// do some formatting if the encapsulating type is an array
|
||||||
|
return `The list of ${capitalize(typeArgumentDoc) || this.defaultSummary}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.knowledgeBaseFactory.tryToGetSummary({
|
||||||
|
...knowledgeBaseOptions,
|
||||||
|
str: this.checker.typeToString(nodeType),
|
||||||
|
}) || ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the docblock of a symbol. It tries to retrieve it using the symbol's `getDocumentationComment` and `getJsDocTags`
|
||||||
|
* methods. If both methods don't return any comments, it tries to get the comments from the {@link KnowledgeBaseFactory}.
|
||||||
|
*
|
||||||
|
* @param {ts.Symbol} symbol - The symbol to retrieve its docblock.
|
||||||
|
* @returns {string} The symbol's docblock.
|
||||||
|
*/
|
||||||
|
private getSymbolDocBlock(
|
||||||
|
symbol: ts.Symbol,
|
||||||
|
knowledgeBaseOptions?: Partial<RetrieveOptions>
|
||||||
|
): string {
|
||||||
|
const commentDisplayParts = symbol.getDocumentationComment(this.checker)
|
||||||
|
if (!commentDisplayParts.length) {
|
||||||
|
// try to get description from the first JSDoc comment
|
||||||
|
const jsdocComments = symbol.getJsDocTags(this.checker)
|
||||||
|
|
||||||
|
if (jsdocComments.length) {
|
||||||
|
jsdocComments
|
||||||
|
.find((tag) => (tag.text?.length || 0) > 0)
|
||||||
|
?.text!.forEach((tagText) => {
|
||||||
|
commentDisplayParts.push(tagText)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commentDisplayParts.length) {
|
||||||
|
return (
|
||||||
|
this.knowledgeBaseFactory.tryToGetSummary({
|
||||||
|
...knowledgeBaseOptions,
|
||||||
|
str: this.checker.typeToString(this.checker.getTypeOfSymbol(symbol)),
|
||||||
|
}) ||
|
||||||
|
this.knowledgeBaseFactory.tryToGetSummary({
|
||||||
|
...knowledgeBaseOptions,
|
||||||
|
str: symbol.name,
|
||||||
|
}) ||
|
||||||
|
""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts
|
||||||
|
.displayPartsToString(commentDisplayParts)
|
||||||
|
.replaceAll("\n", DOCBLOCK_NEW_LINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves docblocks based on decorators used on a symbol.
|
||||||
|
*
|
||||||
|
* @param {ts.Symbol} symbol - The symbol to retrieve its decorators docblock.
|
||||||
|
* @returns {string} The symbol's decorators docblock.
|
||||||
|
*/
|
||||||
|
getDecoratorDocs(symbol: ts.Symbol): string {
|
||||||
|
let str = ""
|
||||||
|
|
||||||
|
symbol.declarations?.forEach((declaration) => {
|
||||||
|
const modifiers =
|
||||||
|
"modifiers" in declaration && declaration.modifiers
|
||||||
|
? (declaration.modifiers as ts.NodeArray<ts.Modifier>)
|
||||||
|
: []
|
||||||
|
|
||||||
|
modifiers.forEach((modifier) => {
|
||||||
|
if (!ts.isDecorator(modifier)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for decorator text
|
||||||
|
;(modifier as ts.Decorator).forEachChild((childNode) => {
|
||||||
|
if (ts.isCallExpression(childNode)) {
|
||||||
|
const childNodeExpression = (childNode as ts.CallExpression)
|
||||||
|
.expression
|
||||||
|
if (ts.isIdentifier(childNodeExpression)) {
|
||||||
|
switch (childNodeExpression.escapedText) {
|
||||||
|
case "FeatureFlagEntity":
|
||||||
|
// add the `@featureFlag` tag.
|
||||||
|
str += `${DOCBLOCK_DOUBLE_LINES}@featureFlag [flag_name]`
|
||||||
|
break
|
||||||
|
case "BeforeInsert":
|
||||||
|
case "BeforeLoad":
|
||||||
|
case "AfterLoad":
|
||||||
|
// add `@apiIgnore` tag
|
||||||
|
str += `${DOCBLOCK_DOUBLE_LINES}@apiIgnore`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve docblocks that are common to all nodes, despite their kind.
|
||||||
|
*
|
||||||
|
* @param {T | ts.Node} node - The node to retrieve its common doc blocks.
|
||||||
|
* @param {CommonDocsOptions} options - Formatting options.
|
||||||
|
* @returns {string} The common docblocks.
|
||||||
|
*/
|
||||||
|
getCommonDocs(
|
||||||
|
node: T | ts.Node,
|
||||||
|
options: CommonDocsOptions = { addDefaultSummary: false }
|
||||||
|
): string {
|
||||||
|
const tags = new Set<string>()
|
||||||
|
|
||||||
|
const symbol = getSymbol(node, this.checker)
|
||||||
|
|
||||||
|
if (!symbol) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ts.isSourceFile(node)) {
|
||||||
|
// comments for source files must start with this tag
|
||||||
|
tags.add(`@packageDocumentation`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.addDefaultSummary) {
|
||||||
|
tags.add(this.defaultSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for private or protected modifiers
|
||||||
|
// and if found, add the `@ignore` tag.
|
||||||
|
symbol.declarations?.some((declaration) => {
|
||||||
|
if (!("modifiers" in declaration) || !declaration.modifiers) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasPrivateOrProtected = (
|
||||||
|
declaration.modifiers as ts.NodeArray<ts.Modifier>
|
||||||
|
).find((modifier) => {
|
||||||
|
modifier.kind === ts.SyntaxKind.PrivateKeyword ||
|
||||||
|
modifier.kind === ts.SyntaxKind.ProtectedKeyword
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasPrivateOrProtected) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.add("@ignore")
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// if a symbol's name starts with `_` then we
|
||||||
|
// should add the `@ignore` tag
|
||||||
|
if (symbol.getName().startsWith("_")) {
|
||||||
|
tags.add("@ignore")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if any docs can be added for the symbol's
|
||||||
|
// decorators
|
||||||
|
this.getDecoratorDocs(symbol)
|
||||||
|
.split(`${DOCBLOCK_DOUBLE_LINES}`)
|
||||||
|
.filter((docItem) => docItem.length > 0)
|
||||||
|
.forEach((docItem) => tags.add(docItem))
|
||||||
|
|
||||||
|
// add `@expandable` tag if the resource is
|
||||||
|
if (ts.isPropertyDeclaration(node)) {
|
||||||
|
const symbolType = this.checker.getTypeOfSymbol(symbol)
|
||||||
|
if (
|
||||||
|
symbolType.symbol?.declarations?.length &&
|
||||||
|
ts.isClassDeclaration(symbolType.symbol?.declarations[0]) &&
|
||||||
|
this.isEntity({
|
||||||
|
heritageClauses: (
|
||||||
|
symbolType.symbol?.declarations[0] as ts.ClassDeclaration
|
||||||
|
).heritageClauses,
|
||||||
|
node: symbolType.symbol?.declarations[0],
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
tags.add(`@expandable`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if custom namespace should be added
|
||||||
|
if (shouldHaveCustomNamespace(node)) {
|
||||||
|
tags.add(getCustomNamespaceTag(node))
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for default value
|
||||||
|
if (
|
||||||
|
"initializer" in node &&
|
||||||
|
node.initializer &&
|
||||||
|
ts.isExpression(node.initializer as ts.Node)
|
||||||
|
) {
|
||||||
|
const initializer = node.initializer as ts.Expression
|
||||||
|
|
||||||
|
// retrieve default value only if the value is numeric, string, or boolean
|
||||||
|
const defaultValue =
|
||||||
|
ts.isNumericLiteral(initializer) || ts.isStringLiteral(initializer)
|
||||||
|
? initializer.getText()
|
||||||
|
: initializer.kind === ts.SyntaxKind.FalseKeyword
|
||||||
|
? "false"
|
||||||
|
: initializer.kind === ts.SyntaxKind.TrueKeyword
|
||||||
|
? "true"
|
||||||
|
: ""
|
||||||
|
|
||||||
|
if (defaultValue.length) {
|
||||||
|
tags.add(`@defaultValue ${defaultValue}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = ""
|
||||||
|
tags.forEach((tag) => {
|
||||||
|
if (str.length > 0) {
|
||||||
|
str += `${DOCBLOCK_DOUBLE_LINES}`
|
||||||
|
}
|
||||||
|
str += `${tag}`
|
||||||
|
})
|
||||||
|
|
||||||
|
if (str.length && options.prefixWithLineBreaks) {
|
||||||
|
str = `${DOCBLOCK_DOUBLE_LINES}${str}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node is a Medusa entity.
|
||||||
|
* @returns {boolean} Whether the node is a Medusa entity.
|
||||||
|
*/
|
||||||
|
isEntity({
|
||||||
|
/**
|
||||||
|
* The inherit/extend keywords of the node.
|
||||||
|
*/
|
||||||
|
heritageClauses,
|
||||||
|
/**
|
||||||
|
* Optionally provide the node to accurately retrieve its type name.
|
||||||
|
*/
|
||||||
|
node,
|
||||||
|
}: {
|
||||||
|
heritageClauses?: ts.NodeArray<ts.HeritageClause>
|
||||||
|
node?: ts.Node
|
||||||
|
}): boolean {
|
||||||
|
return (
|
||||||
|
heritageClauses?.some((heritageClause) => {
|
||||||
|
return heritageClause.types.some((heritageClauseType) => {
|
||||||
|
const symbolType = this.checker.getTypeAtLocation(
|
||||||
|
heritageClauseType.expression
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.checker
|
||||||
|
.typeToString(symbolType, node, undefined)
|
||||||
|
.includes("BaseEntity")
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
symbolType.symbol.valueDeclaration &&
|
||||||
|
"heritageClauses" in symbolType.symbol.valueDeclaration
|
||||||
|
) {
|
||||||
|
return this.isEntity({
|
||||||
|
heritageClauses: symbolType.symbol.valueDeclaration
|
||||||
|
.heritageClauses as ts.NodeArray<ts.HeritageClause>,
|
||||||
|
node,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}) || false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getKnowledgeOptions(node: ts.Node): Partial<RetrieveOptions> {
|
||||||
|
const rawParentName =
|
||||||
|
"name" in node.parent &&
|
||||||
|
node.parent.name &&
|
||||||
|
ts.isIdentifier(node.parent.name as ts.Node)
|
||||||
|
? (node.parent.name as ts.Identifier).getText()
|
||||||
|
: undefined
|
||||||
|
return {
|
||||||
|
kind: node.kind,
|
||||||
|
templateOptions: {
|
||||||
|
rawParentName,
|
||||||
|
parentName: rawParentName
|
||||||
|
? camelToWords(normalizeName(rawParentName))
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DefaultKindGenerator
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import DefaultKindGenerator, { GetDocBlockOptions } from "./default.js"
|
||||||
|
import { DOCBLOCK_END_LINE, DOCBLOCK_START } from "../../constants.js"
|
||||||
|
import {
|
||||||
|
camelToWords,
|
||||||
|
normalizeName,
|
||||||
|
snakeToWords,
|
||||||
|
} from "../../utils/str-formatting.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that generates doc blocks for properties in a DTO interface/type.
|
||||||
|
*/
|
||||||
|
class DTOPropertyGenerator extends DefaultKindGenerator<ts.PropertySignature> {
|
||||||
|
protected allowedKinds: ts.SyntaxKind[] = [ts.SyntaxKind.PropertySignature]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the generator can handle generating for the node.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the generator can handle generating for the node.
|
||||||
|
*/
|
||||||
|
isAllowed(node: ts.Node): node is ts.PropertySignature {
|
||||||
|
if (!super.isAllowed(node)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.getParentName((node as ts.PropertySignature).parent).endsWith(
|
||||||
|
"DTO"
|
||||||
|
) || false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getDocBlock(
|
||||||
|
node: ts.PropertyDeclaration | ts.Node,
|
||||||
|
options?: GetDocBlockOptions
|
||||||
|
): string {
|
||||||
|
if (!this.isAllowed(node)) {
|
||||||
|
return super.getDocBlock(node, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = DOCBLOCK_START
|
||||||
|
const rawParentName = this.getParentName(node.parent)
|
||||||
|
const parentName = this.formatInterfaceName(rawParentName)
|
||||||
|
|
||||||
|
// try first to retrieve the summary from the knowledge base if it exists.
|
||||||
|
const summary = this.knowledgeBaseFactory.tryToGetSummary({
|
||||||
|
str: node.name.getText(),
|
||||||
|
kind: node.kind,
|
||||||
|
templateOptions: {
|
||||||
|
rawParentName,
|
||||||
|
parentName,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (summary) {
|
||||||
|
str += summary
|
||||||
|
} else {
|
||||||
|
// check if the property's type is interface/type/class
|
||||||
|
const propertyType = this.checker.getTypeAtLocation(node)
|
||||||
|
if (propertyType.isClassOrInterface()) {
|
||||||
|
str += `The associated ${this.formatInterfaceName(
|
||||||
|
this.checker.typeToString(propertyType)
|
||||||
|
)}.`
|
||||||
|
} else if (
|
||||||
|
"intrinsicName" in propertyType &&
|
||||||
|
propertyType.intrinsicName === "boolean"
|
||||||
|
) {
|
||||||
|
str += `Whether the ${parentName} ${snakeToWords(node.name.getText())}.`
|
||||||
|
} else {
|
||||||
|
// format summary
|
||||||
|
str += `The ${snakeToWords(node.name.getText())} of the ${parentName}.`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${str}${DOCBLOCK_END_LINE}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the name of the interface/type.
|
||||||
|
*
|
||||||
|
* @param {string} name - The name to format.
|
||||||
|
* @returns {string} The formatted name.
|
||||||
|
*/
|
||||||
|
formatInterfaceName(name: string): string {
|
||||||
|
return camelToWords(normalizeName(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the parent interface/type.
|
||||||
|
*
|
||||||
|
* @param {ts.InterfaceDeclaration | ts.TypeLiteralNode} parent - The parent node.
|
||||||
|
* @returns {string} The name of the parent.
|
||||||
|
*/
|
||||||
|
getParentName(parent: ts.InterfaceDeclaration | ts.TypeLiteralNode): string {
|
||||||
|
if (ts.isInterfaceDeclaration(parent)) {
|
||||||
|
return parent.name.getText()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.checker.typeToString(this.checker.getTypeFromTypeNode(parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DTOPropertyGenerator
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import DefaultKindGenerator, { GetDocBlockOptions } from "./default.js"
|
||||||
|
import {
|
||||||
|
DOCBLOCK_NEW_LINE,
|
||||||
|
DOCBLOCK_END_LINE,
|
||||||
|
DOCBLOCK_START,
|
||||||
|
DOCBLOCK_DOUBLE_LINES,
|
||||||
|
} from "../../constants.js"
|
||||||
|
import getSymbol from "../../utils/get-symbol.js"
|
||||||
|
|
||||||
|
export type FunctionNode =
|
||||||
|
| ts.MethodDeclaration
|
||||||
|
| ts.MethodSignature
|
||||||
|
| ts.FunctionDeclaration
|
||||||
|
| ts.ArrowFunction
|
||||||
|
|
||||||
|
type VariableNode = ts.VariableDeclaration | ts.VariableStatement
|
||||||
|
|
||||||
|
export type FunctionOrVariableNode = FunctionNode | ts.VariableStatement
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Docblock generator for functions.
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
class FunctionKindGenerator extends DefaultKindGenerator<FunctionOrVariableNode> {
|
||||||
|
protected methodKinds: ts.SyntaxKind[] = [
|
||||||
|
ts.SyntaxKind.MethodDeclaration,
|
||||||
|
ts.SyntaxKind.MethodSignature,
|
||||||
|
]
|
||||||
|
protected functionKinds: ts.SyntaxKind[] = [ts.SyntaxKind.FunctionDeclaration]
|
||||||
|
protected allowedKinds: ts.SyntaxKind[] = [
|
||||||
|
...this.methodKinds,
|
||||||
|
...this.functionKinds,
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node is considered a function node. A node is considered a function node if:
|
||||||
|
*
|
||||||
|
* 1. It is a method declaration (typically in classes), a method signature (typically in interfaces), or a function declaration.
|
||||||
|
* 2. An arrow function. However, for better docblock placement and formatting, we detect the variable statement surrounding the arrow function
|
||||||
|
* rather than the arrow function itself.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the node is a function node and can be handled by this generator.
|
||||||
|
*/
|
||||||
|
isAllowed(node: ts.Node): node is FunctionOrVariableNode {
|
||||||
|
if (!super.isAllowed(node)) {
|
||||||
|
return ts.isVariableStatement(node) && this.isFunctionVariable(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node is a variable statement/declaration with underlying node function
|
||||||
|
* using the {@link extractFunctionNode} method.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the node is a variable statement/declaration with underlying node function.
|
||||||
|
*/
|
||||||
|
isFunctionVariable(node: ts.Node): node is VariableNode {
|
||||||
|
if (ts.isVariableStatement(node)) {
|
||||||
|
return node.declarationList.declarations.some((declaration) => {
|
||||||
|
return this.isFunctionVariable(declaration)
|
||||||
|
})
|
||||||
|
} else if (ts.isVariableDeclaration(node)) {
|
||||||
|
return this.extractFunctionNode(node) !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the underlying function/method/arrow function of a variable statement or declaration.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The variable statement/declaration to retrieve the function/method from.
|
||||||
|
* @returns The function/method if found.
|
||||||
|
*/
|
||||||
|
extractFunctionNode(node: VariableNode): FunctionNode | undefined {
|
||||||
|
if (ts.isVariableStatement(node)) {
|
||||||
|
const variableDeclaration = node.declarationList.declarations.find(
|
||||||
|
(declaration) => ts.isVariableDeclaration(declaration)
|
||||||
|
)
|
||||||
|
|
||||||
|
return variableDeclaration
|
||||||
|
? this.extractFunctionNode(variableDeclaration)
|
||||||
|
: undefined
|
||||||
|
} else if (
|
||||||
|
node.initializer &&
|
||||||
|
(this.isAllowed(node.initializer) || ts.isArrowFunction(node.initializer))
|
||||||
|
) {
|
||||||
|
return node.initializer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a node refers to a method.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the node is a method.
|
||||||
|
*/
|
||||||
|
isMethod(
|
||||||
|
node: FunctionNode
|
||||||
|
): node is ts.MethodDeclaration | ts.MethodSignature {
|
||||||
|
return this.methodKinds.includes(node.kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a type, typically the type of a function's signature, has return data.
|
||||||
|
*
|
||||||
|
* @param {string} typeStr - The type's string representation.
|
||||||
|
* @returns {boolean} Whether the type has return data.
|
||||||
|
*/
|
||||||
|
hasReturnData(typeStr: string): boolean {
|
||||||
|
return (
|
||||||
|
typeStr !== "void" &&
|
||||||
|
typeStr !== "never" &&
|
||||||
|
typeStr !== "Promise<void>" &&
|
||||||
|
typeStr !== "Promise<never>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the return type of a function.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The function's node.
|
||||||
|
* @returns {ts.Type} The function's return type.
|
||||||
|
*/
|
||||||
|
getReturnType(node: FunctionNode): ts.Type {
|
||||||
|
return node.type
|
||||||
|
? this.checker.getTypeFromTypeNode(node.type)
|
||||||
|
: this.checker.getTypeAtLocation(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the summary comment of a function.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The node's function.
|
||||||
|
* @param {ts.Symbol} symbol - The node's symbol. If provided, the method will try to retrieve the summary from the {@link KnowledgeBaseFactory}.
|
||||||
|
* @returns {string} The function's summary comment.
|
||||||
|
*/
|
||||||
|
getFunctionSummary(node: FunctionNode, symbol?: ts.Symbol): string {
|
||||||
|
return symbol
|
||||||
|
? this.knowledgeBaseFactory.tryToGetFunctionSummary({
|
||||||
|
symbol: symbol,
|
||||||
|
kind: node.kind,
|
||||||
|
}) || this.getNodeSummary({ node, symbol })
|
||||||
|
: this.getNodeSummary({ node, symbol })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the function's example comment.
|
||||||
|
*
|
||||||
|
* @param {ts.Symbol} symbol - The function's symbol. If provided, the method will try to retrieve the example from the {@link KnowledgeBaseFactory}.
|
||||||
|
* @returns {string} The function's example comment.
|
||||||
|
*/
|
||||||
|
getFunctionExample(symbol?: ts.Symbol): string {
|
||||||
|
const str = `${DOCBLOCK_DOUBLE_LINES}@example${DOCBLOCK_NEW_LINE}`
|
||||||
|
return `${str}${
|
||||||
|
symbol
|
||||||
|
? this.knowledgeBaseFactory.tryToGetFunctionExamples({
|
||||||
|
symbol: symbol,
|
||||||
|
}) || `{example-code}`
|
||||||
|
: `{example-code}`
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the full docblock of a function.
|
||||||
|
*
|
||||||
|
* @param {FunctionOrVariableNode | ts.Node} node - The function node. If a variable statement is provided, the underlying function is retrieved.
|
||||||
|
* If a different node type is provided, the parent generator is used to retrieve the docblock comment.
|
||||||
|
* @param {GetDocBlockOptions} options - Formatting options.
|
||||||
|
* @returns {string} The function's docblock.
|
||||||
|
*/
|
||||||
|
getDocBlock(
|
||||||
|
node: FunctionOrVariableNode | ts.Node,
|
||||||
|
options: GetDocBlockOptions = { addEnd: true }
|
||||||
|
): string {
|
||||||
|
if (!this.isAllowed(node)) {
|
||||||
|
return super.getDocBlock(node, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
const actualNode = ts.isVariableStatement(node)
|
||||||
|
? this.extractFunctionNode(node)
|
||||||
|
: node
|
||||||
|
|
||||||
|
if (!actualNode) {
|
||||||
|
return super.getDocBlock(node, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeSymbol = getSymbol(node, this.checker)
|
||||||
|
|
||||||
|
let str = DOCBLOCK_START
|
||||||
|
|
||||||
|
// add summary
|
||||||
|
str += `${
|
||||||
|
options.summaryPrefix ||
|
||||||
|
(this.isMethod(actualNode) ? `This method` : `This function`)
|
||||||
|
} ${this.getFunctionSummary(actualNode, nodeSymbol)}${DOCBLOCK_NEW_LINE}`
|
||||||
|
|
||||||
|
// add params
|
||||||
|
actualNode.forEachChild((childNode) => {
|
||||||
|
if (!ts.isParameter(childNode)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const symbol = getSymbol(childNode, this.checker)
|
||||||
|
if (!symbol) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const symbolType = this.checker.getTypeOfSymbolAtLocation(
|
||||||
|
symbol,
|
||||||
|
childNode
|
||||||
|
)
|
||||||
|
|
||||||
|
str += `${DOCBLOCK_NEW_LINE}@param {${this.checker.typeToString(
|
||||||
|
symbolType
|
||||||
|
)}} ${symbol.getName()} - ${this.getNodeSummary({
|
||||||
|
node: childNode,
|
||||||
|
symbol,
|
||||||
|
nodeType: symbolType,
|
||||||
|
})}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// add returns
|
||||||
|
const nodeType = this.getReturnType(actualNode)
|
||||||
|
const returnTypeStr = this.checker.typeToString(nodeType)
|
||||||
|
const possibleReturnSummary = !this.hasReturnData(returnTypeStr)
|
||||||
|
? `Resolves when ${this.defaultSummary}`
|
||||||
|
: this.getNodeSummary({
|
||||||
|
node: actualNode,
|
||||||
|
nodeType,
|
||||||
|
})
|
||||||
|
|
||||||
|
str += `${DOCBLOCK_NEW_LINE}@returns {${returnTypeStr}} ${
|
||||||
|
nodeSymbol
|
||||||
|
? this.knowledgeBaseFactory.tryToGetFunctionReturns({
|
||||||
|
symbol: nodeSymbol,
|
||||||
|
kind: actualNode.kind,
|
||||||
|
}) || possibleReturnSummary
|
||||||
|
: possibleReturnSummary
|
||||||
|
}`
|
||||||
|
|
||||||
|
// add example
|
||||||
|
str += this.getFunctionExample(nodeSymbol)
|
||||||
|
|
||||||
|
// add common docs
|
||||||
|
str += this.getCommonDocs(node, {
|
||||||
|
prefixWithLineBreaks: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (options.addEnd) {
|
||||||
|
str += DOCBLOCK_END_LINE
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FunctionKindGenerator
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import FunctionKindGenerator, {
|
||||||
|
FunctionNode,
|
||||||
|
FunctionOrVariableNode,
|
||||||
|
} from "./function.js"
|
||||||
|
import {
|
||||||
|
DOCBLOCK_NEW_LINE,
|
||||||
|
DOCBLOCK_END_LINE,
|
||||||
|
DOCBLOCK_START,
|
||||||
|
DOCBLOCK_DOUBLE_LINES,
|
||||||
|
} from "../../constants.js"
|
||||||
|
import nodeHasComments from "../../utils/node-has-comments.js"
|
||||||
|
import {
|
||||||
|
CUSTOM_NAMESPACE_TAG,
|
||||||
|
getCustomNamespaceTag,
|
||||||
|
} from "../../utils/medusa-react-utils.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Docblock generate for medusa-react hooks. Since hooks are essentially functions,
|
||||||
|
* it extends the {@link FunctionKindGenerator} class.
|
||||||
|
*/
|
||||||
|
class MedusaReactHooksKindGenerator extends FunctionKindGenerator {
|
||||||
|
/**
|
||||||
|
* Checks whether the generator can retrieve the docblock of the specified node. It uses the parent generator
|
||||||
|
* to check that the node is a function, then checks if the function is a mutation using the {@link isMutation} method,
|
||||||
|
* or a query using the {@link isQuery} method.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether this generator can be used on this node.
|
||||||
|
*/
|
||||||
|
isAllowed(node: ts.Node): node is FunctionOrVariableNode {
|
||||||
|
if (!super.isAllowed(node)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const actualNode = ts.isVariableStatement(node)
|
||||||
|
? this.extractFunctionNode(node)
|
||||||
|
: node
|
||||||
|
|
||||||
|
return (
|
||||||
|
actualNode !== undefined &&
|
||||||
|
(this.isMutation(actualNode) || this.isQuery(actualNode))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a function node is a mutation.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The function node to check.
|
||||||
|
* @returns {boolean} Whether the node is a mutation.
|
||||||
|
*/
|
||||||
|
isMutation(node: FunctionNode): boolean {
|
||||||
|
const nodeType = this.getReturnType(node)
|
||||||
|
|
||||||
|
const callSignatures = nodeType.getCallSignatures()
|
||||||
|
|
||||||
|
return (
|
||||||
|
callSignatures.length > 0 &&
|
||||||
|
this.checker
|
||||||
|
.typeToString(this.checker.getReturnTypeOfSignature(callSignatures[0]))
|
||||||
|
.startsWith("UseMutationResult")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a function node is a query.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The function node to check.
|
||||||
|
* @returns {boolean} Whether the node is a query.
|
||||||
|
*/
|
||||||
|
isQuery(node: FunctionNode): boolean {
|
||||||
|
return node.parameters.some(
|
||||||
|
(parameter) =>
|
||||||
|
parameter.type?.getText().startsWith("UseQueryOptionsWrapper")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the docblock of the medusa-react hook or mutation.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode & ts.VariableDeclaration} node - The node to retrieve its docblock.
|
||||||
|
* @returns {string} The node's docblock.
|
||||||
|
*/
|
||||||
|
getDocBlock(node: FunctionNode & ts.VariableDeclaration): string {
|
||||||
|
if (!this.isAllowed(node)) {
|
||||||
|
return super.getDocBlock(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
const actualNode = ts.isVariableStatement(node)
|
||||||
|
? this.extractFunctionNode(node)
|
||||||
|
: node
|
||||||
|
|
||||||
|
if (!actualNode) {
|
||||||
|
return super.getDocBlock(node)
|
||||||
|
}
|
||||||
|
const isMutation = this.isMutation(actualNode)
|
||||||
|
|
||||||
|
let str = `${DOCBLOCK_START}This hook ${this.getFunctionSummary(node)}`
|
||||||
|
|
||||||
|
// add example
|
||||||
|
str += this.getFunctionExample()
|
||||||
|
|
||||||
|
// loop over parameters that aren't query/mutation parameters
|
||||||
|
// and add docblock to them
|
||||||
|
this.getActualParameters(actualNode).forEach((parameter) => {
|
||||||
|
ts.addSyntheticLeadingComment(
|
||||||
|
parameter,
|
||||||
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
||||||
|
super.getDocBlock(parameter),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// check if mutation parameter is an intrinsic type and, if so, add the `@typeParamDefinition`
|
||||||
|
// tag to the hook
|
||||||
|
if (isMutation) {
|
||||||
|
const typeArg = this.getMutationRequestTypeArg(actualNode)
|
||||||
|
if (typeArg) {
|
||||||
|
str += `${DOCBLOCK_DOUBLE_LINES}@typeParamDefinition ${this.checker.typeToString(
|
||||||
|
typeArg
|
||||||
|
)} - {summary}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add common docs
|
||||||
|
str += this.getCommonDocs(node, {
|
||||||
|
prefixWithLineBreaks: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// add namespace in case it's not added
|
||||||
|
if (!str.includes(CUSTOM_NAMESPACE_TAG)) {
|
||||||
|
str += `${DOCBLOCK_DOUBLE_LINES}${getCustomNamespaceTag(actualNode)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the category
|
||||||
|
str += `${DOCBLOCK_NEW_LINE}@category ${
|
||||||
|
isMutation ? "Mutations" : "Queries"
|
||||||
|
}`
|
||||||
|
|
||||||
|
return `${str}${DOCBLOCK_END_LINE}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the parameters of a function node that aren't query/mutation options.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The function node to retrieve its parameters.
|
||||||
|
* @returns {ts.ParameterDeclaration[]} - The function's actual parameters.
|
||||||
|
*/
|
||||||
|
getActualParameters(node: FunctionNode): ts.ParameterDeclaration[] {
|
||||||
|
return node.parameters.filter((parameter) => {
|
||||||
|
const parameterTypeStr = parameter.type?.getText()
|
||||||
|
return (
|
||||||
|
!parameterTypeStr?.startsWith("UseQueryOptionsWrapper") &&
|
||||||
|
!parameterTypeStr?.startsWith("UseMutationOptions") &&
|
||||||
|
!nodeHasComments(parameter)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreives a mutation's intrinsic request type, if available, which is specified as the third type argument of `UseMutationOptions`.
|
||||||
|
*
|
||||||
|
* @param {FunctionNode} node - The function node to retrieve its request type.
|
||||||
|
* @returns {ts.Type | undefined} The mutation's request type, if available.
|
||||||
|
*/
|
||||||
|
getMutationRequestTypeArg(node: FunctionNode): ts.Type | undefined {
|
||||||
|
const parameter = node.parameters.find(
|
||||||
|
(parameter) => parameter.type?.getText().startsWith("UseMutationOptions")
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!parameter) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const parameterType = this.checker.getTypeFromTypeNode(parameter.type!)
|
||||||
|
const typeArgs =
|
||||||
|
parameterType.aliasTypeArguments ||
|
||||||
|
("resolvedTypeArguments" in parameterType
|
||||||
|
? (parameterType.resolvedTypeArguments as ts.Type[])
|
||||||
|
: [])
|
||||||
|
if (
|
||||||
|
!typeArgs ||
|
||||||
|
typeArgs.length < 3 ||
|
||||||
|
!("intrinsicName" in typeArgs[2]) ||
|
||||||
|
["void", "unknown"].includes(typeArgs[2].intrinsicName as string)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// find request in third type argument
|
||||||
|
return typeArgs[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MedusaReactHooksKindGenerator
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import FunctionKindGenerator from "./function.js"
|
||||||
|
import DefaultKindGenerator from "./default.js"
|
||||||
|
import MedusaReactHooksKindGenerator from "./medusa-react-hooks.js"
|
||||||
|
import SourceFileKindGenerator from "./source-file.js"
|
||||||
|
import DTOPropertyGenerator from "./dto-property.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that is used as a registry for the kind generators.
|
||||||
|
*/
|
||||||
|
class KindsRegistry {
|
||||||
|
protected kindInstances: DefaultKindGenerator[]
|
||||||
|
protected defaultKindGenerator: DefaultKindGenerator
|
||||||
|
|
||||||
|
constructor(checker: ts.TypeChecker) {
|
||||||
|
this.kindInstances = [
|
||||||
|
new MedusaReactHooksKindGenerator({ checker }),
|
||||||
|
new FunctionKindGenerator({ checker }),
|
||||||
|
new SourceFileKindGenerator({ checker }),
|
||||||
|
new DTOPropertyGenerator({ checker }),
|
||||||
|
]
|
||||||
|
this.defaultKindGenerator = new DefaultKindGenerator({ checker })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the generator for a node based on its kind, if any.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to retrieve its docblock generator.
|
||||||
|
* @returns {DefaultKindGenerator | undefined} The generator that can handle the node's kind, if any.
|
||||||
|
*/
|
||||||
|
getKindGenerator(node: ts.Node): DefaultKindGenerator | undefined {
|
||||||
|
return (
|
||||||
|
this.kindInstances.find((generator) => generator.isAllowed(node)) ||
|
||||||
|
(this.defaultKindGenerator.isAllowed(node)
|
||||||
|
? this.defaultKindGenerator
|
||||||
|
: undefined)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node has a kind generator.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check for.
|
||||||
|
* @returns {boolean} Whether the node has a kind generator.
|
||||||
|
*/
|
||||||
|
hasGenerator(node: ts.Node): boolean {
|
||||||
|
return this.getKindGenerator(node) !== undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KindsRegistry
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import DefaultKindGenerator, { GetDocBlockOptions } from "./default.js"
|
||||||
|
import { DOCBLOCK_END_LINE, DOCBLOCK_START } from "../../constants.js"
|
||||||
|
import { shouldHaveCustomNamespace } from "../../utils/medusa-react-utils.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generator used to retrieve doc blocks for a source file.
|
||||||
|
*/
|
||||||
|
class SourceFileKindGenerator extends DefaultKindGenerator<ts.SourceFile> {
|
||||||
|
protected allowedKinds: ts.SyntaxKind[] = [ts.SyntaxKind.SourceFile]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the docblock of a source file.
|
||||||
|
*
|
||||||
|
* @param {ts.SourceFile | ts.Node} node - The node to retrieve its docblocks.
|
||||||
|
* @param {GetDocBlockOptions} options - The formatting options.
|
||||||
|
* @returns {string} The node's docblock.
|
||||||
|
*/
|
||||||
|
getDocBlock(
|
||||||
|
node: ts.SourceFile | ts.Node,
|
||||||
|
options?: GetDocBlockOptions
|
||||||
|
): string {
|
||||||
|
if (!this.isAllowed(node)) {
|
||||||
|
return super.getDocBlock(node, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldHaveCustomNamespace(node)) {
|
||||||
|
return `${DOCBLOCK_START}${this.getCommonDocs(node, {
|
||||||
|
addDefaultSummary: true,
|
||||||
|
})}${DOCBLOCK_END_LINE}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SourceFileKindGenerator
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
import { DOCBLOCK_DOUBLE_LINES, DOCBLOCK_NEW_LINE } from "../constants.js"
|
||||||
|
import {
|
||||||
|
camelToTitle,
|
||||||
|
camelToWords,
|
||||||
|
normalizeName,
|
||||||
|
} from "../utils/str-formatting.js"
|
||||||
|
|
||||||
|
type TemplateOptions = {
|
||||||
|
parentName?: string
|
||||||
|
rawParentName?: string
|
||||||
|
returnTypeName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type KnowledgeBase = {
|
||||||
|
startsWith?: string
|
||||||
|
endsWith?: string
|
||||||
|
exact?: string
|
||||||
|
template: string | ((str: string, options?: TemplateOptions) => string)
|
||||||
|
kind?: ts.SyntaxKind[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RetrieveOptions = {
|
||||||
|
/**
|
||||||
|
* A name that can be of a function, type, etc...
|
||||||
|
*/
|
||||||
|
str: string
|
||||||
|
/**
|
||||||
|
* Options to pass to the `template` function of a
|
||||||
|
* knowledge base item.
|
||||||
|
*/
|
||||||
|
templateOptions?: TemplateOptions
|
||||||
|
/**
|
||||||
|
* The kind of the associated node.
|
||||||
|
*/
|
||||||
|
kind?: ts.SyntaxKind
|
||||||
|
}
|
||||||
|
|
||||||
|
type RetrieveSymbolOptions = Omit<RetrieveOptions, "str"> & {
|
||||||
|
/**
|
||||||
|
* The symbol to retrieve the item from the knowledge base.
|
||||||
|
*/
|
||||||
|
symbol: ts.Symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that holds common Medusa patterns and acts as a knowledge base for possible summaries/examples/general templates.
|
||||||
|
*/
|
||||||
|
class KnowledgeBaseFactory {
|
||||||
|
private summaryKnowledgeBase: KnowledgeBase[] = [
|
||||||
|
{
|
||||||
|
startsWith: "FindConfig",
|
||||||
|
template: (str) => {
|
||||||
|
const typeArgs = str
|
||||||
|
.replace("FindConfig<", "")
|
||||||
|
.replace(/>$/, "")
|
||||||
|
.split(",")
|
||||||
|
.map((part) => camelToWords(normalizeName(part.trim())))
|
||||||
|
const typeName =
|
||||||
|
typeArgs.length > 0 && typeArgs[0].length > 0
|
||||||
|
? typeArgs[0]
|
||||||
|
: `{type name}`
|
||||||
|
return `The configurations determining how the ${typeName} is retrieved. Its properties, such as \`select\` or \`relations\`, accept the ${DOCBLOCK_NEW_LINE}attributes or relations associated with a ${typeName}.`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "Filterable",
|
||||||
|
endsWith: "Props",
|
||||||
|
template: (str) => {
|
||||||
|
return `The filters to apply on the retrieved ${camelToTitle(
|
||||||
|
normalizeName(str)
|
||||||
|
)}.`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "Create",
|
||||||
|
endsWith: "DTO",
|
||||||
|
template: (str) => {
|
||||||
|
return `The ${camelToTitle(normalizeName(str))} to be created.`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "Update",
|
||||||
|
endsWith: "DTO",
|
||||||
|
template: (str) => {
|
||||||
|
return `The attributes to update in the ${camelToTitle(
|
||||||
|
normalizeName(str)
|
||||||
|
)}.`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "RestoreReturn",
|
||||||
|
template: `Configurations determining which relations to restore along with each of the {type name}. You can pass to its \`returnLinkableKeys\` ${DOCBLOCK_NEW_LINE}property any of the {type name}'s relation attribute names, such as \`{type relation name}\`.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
endsWith: "DTO",
|
||||||
|
template: (str: string): string => {
|
||||||
|
return `The ${camelToTitle(normalizeName(str))} details.`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
endsWith: "_id",
|
||||||
|
template: (str: string): string => {
|
||||||
|
const formatted = str.replace(/_id$/, "").split("_").join(" ")
|
||||||
|
|
||||||
|
return `The associated ${formatted}'s ID.`
|
||||||
|
},
|
||||||
|
kind: [ts.SyntaxKind.PropertySignature],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
endsWith: "Id",
|
||||||
|
template: (str: string): string => {
|
||||||
|
const formatted = camelToWords(str.replace(/Id$/, ""))
|
||||||
|
|
||||||
|
return `The ${formatted}'s ID.`
|
||||||
|
},
|
||||||
|
kind: [
|
||||||
|
ts.SyntaxKind.PropertySignature,
|
||||||
|
ts.SyntaxKind.PropertyDeclaration,
|
||||||
|
ts.SyntaxKind.Parameter,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exact: "id",
|
||||||
|
template: (str, options) => {
|
||||||
|
if (options?.rawParentName?.startsWith("Filterable")) {
|
||||||
|
return `The IDs to filter the ${options?.parentName || `{name}`} by.`
|
||||||
|
}
|
||||||
|
return `The ID of the ${options?.parentName || `{name}`}.`
|
||||||
|
},
|
||||||
|
kind: [ts.SyntaxKind.PropertySignature],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exact: "metadata",
|
||||||
|
template: "Holds custom data in key-value pairs.",
|
||||||
|
kind: [ts.SyntaxKind.PropertySignature],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exact: "customHeaders",
|
||||||
|
template: "Custom headers to attach to the request.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
private functionSummaryKnowledgeBase: KnowledgeBase[] = [
|
||||||
|
{
|
||||||
|
startsWith: "listAndCount",
|
||||||
|
template:
|
||||||
|
"retrieves a paginated list of {return type} along with the total count of available {return type}(s) satisfying the provided filters.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "list",
|
||||||
|
template:
|
||||||
|
"retrieves a paginated list of {return type}(s) based on optional filters and configuration.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "retrieve",
|
||||||
|
template: "retrieves a {return type} by its ID.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "create",
|
||||||
|
template: "creates {return type}(s)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "delete",
|
||||||
|
template: "deletes {return type} by its ID.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "update",
|
||||||
|
template: "updates existing {return type}(s).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "softDelete",
|
||||||
|
template: "soft deletes {return type}(s) by their IDs.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "restore",
|
||||||
|
template: "restores soft deleted {return type}(s) by their IDs.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
private exampleCodeBlockLine = `${DOCBLOCK_DOUBLE_LINES}\`\`\`ts${DOCBLOCK_NEW_LINE}{example-code}${DOCBLOCK_NEW_LINE}\`\`\`${DOCBLOCK_DOUBLE_LINES}`
|
||||||
|
private examplesKnowledgeBase: KnowledgeBase[] = [
|
||||||
|
{
|
||||||
|
startsWith: "list",
|
||||||
|
template: `To retrieve a list of {type name} using their IDs: ${this.exampleCodeBlockLine}To specify relations that should be retrieved within the {type name}: ${this.exampleCodeBlockLine}By default, only the first \`{default limit}\` records are retrieved. You can control pagination by specifying the \`skip\` and \`take\` properties of the \`config\` parameter: ${this.exampleCodeBlockLine}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "retrieve",
|
||||||
|
template: `A simple example that retrieves a {type name} by its ID: ${this.exampleCodeBlockLine}To specify relations that should be retrieved: ${this.exampleCodeBlockLine}`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
private functionReturnKnowledgeBase: KnowledgeBase[] = [
|
||||||
|
{
|
||||||
|
startsWith: "listAndCount",
|
||||||
|
template: "The list of {return type}(s) along with their total count.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "list",
|
||||||
|
template: "The list of {return type}(s).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "retrieve",
|
||||||
|
template: "The retrieved {return type}(s).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "create",
|
||||||
|
template: "The created {return type}(s).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "update",
|
||||||
|
template: "The updated {return type}(s).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startsWith: "restore",
|
||||||
|
template: `An object that includes the IDs of related records that were restored, such as the ID of associated {relation name}. ${DOCBLOCK_NEW_LINE}The object's keys are the ID attribute names of the {type name} entity's relations, such as \`{relation ID field name}\`, ${DOCBLOCK_NEW_LINE}and its value is an array of strings, each being the ID of the record associated with the money amount through this relation, ${DOCBLOCK_NEW_LINE}such as the IDs of associated {relation name}.`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find in a specified knowledge base a template relevant to the specified name.
|
||||||
|
*
|
||||||
|
* @returns {string | undefined} The matching knowledge base template, if found.
|
||||||
|
*/
|
||||||
|
private tryToFindInKnowledgeBase({
|
||||||
|
str,
|
||||||
|
knowledgeBase,
|
||||||
|
templateOptions,
|
||||||
|
kind,
|
||||||
|
}: RetrieveOptions & {
|
||||||
|
/**
|
||||||
|
* A knowledge base to search in.
|
||||||
|
*/
|
||||||
|
knowledgeBase: KnowledgeBase[]
|
||||||
|
}): string | undefined {
|
||||||
|
const foundItem = knowledgeBase.find((item) => {
|
||||||
|
if (item.exact) {
|
||||||
|
return str === item.exact
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.kind?.length && (!kind || !item.kind.includes(kind))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.startsWith && item.endsWith) {
|
||||||
|
return str.startsWith(item.startsWith) && str.endsWith(item.endsWith)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.startsWith) {
|
||||||
|
return str.startsWith(item.startsWith)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.endsWith ? str.endsWith(item.endsWith) : false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!foundItem) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof foundItem.template === "string"
|
||||||
|
? foundItem?.template
|
||||||
|
: foundItem?.template(str, templateOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve the summary template of a specified type from the {@link summaryKnowledgeBase}.
|
||||||
|
*
|
||||||
|
* @returns {string | undefined} The matching knowledge base template, if found.
|
||||||
|
*/
|
||||||
|
tryToGetSummary({ str, ...options }: RetrieveOptions): string | undefined {
|
||||||
|
const normalizedTypeStr = str.replaceAll("[]", "")
|
||||||
|
return this.tryToFindInKnowledgeBase({
|
||||||
|
...options,
|
||||||
|
str: normalizedTypeStr,
|
||||||
|
knowledgeBase: this.summaryKnowledgeBase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve the summary template of a function's symbol from the {@link functionSummaryKnowledgeBase}.
|
||||||
|
*
|
||||||
|
* @returns {string | undefined} The matching knowledge base template, if found.
|
||||||
|
*/
|
||||||
|
tryToGetFunctionSummary({
|
||||||
|
symbol,
|
||||||
|
...options
|
||||||
|
}: RetrieveSymbolOptions): string | undefined {
|
||||||
|
return this.tryToFindInKnowledgeBase({
|
||||||
|
...options,
|
||||||
|
str: symbol.getName(),
|
||||||
|
knowledgeBase: this.functionSummaryKnowledgeBase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve the example template of a function's symbol from the {@link examplesKnowledgeBase}.
|
||||||
|
*
|
||||||
|
* @returns {string | undefined} The matching knowledge base template, if found.
|
||||||
|
*/
|
||||||
|
tryToGetFunctionExamples({
|
||||||
|
symbol,
|
||||||
|
...options
|
||||||
|
}: RetrieveSymbolOptions): string | undefined {
|
||||||
|
return this.tryToFindInKnowledgeBase({
|
||||||
|
...options,
|
||||||
|
str: symbol.getName(),
|
||||||
|
knowledgeBase: this.examplesKnowledgeBase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve the return template of a function's symbol from the {@link functionReturnKnowledgeBase}.
|
||||||
|
*
|
||||||
|
* @returns {string | undefined} The matching knowledge base template, if found.
|
||||||
|
*/
|
||||||
|
tryToGetFunctionReturns({
|
||||||
|
symbol,
|
||||||
|
...options
|
||||||
|
}: RetrieveSymbolOptions): string | undefined {
|
||||||
|
return this.tryToFindInKnowledgeBase({
|
||||||
|
...options,
|
||||||
|
str: symbol.getName(),
|
||||||
|
knowledgeBase: this.functionReturnKnowledgeBase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KnowledgeBaseFactory
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import path from "path"
|
||||||
|
import DocblockGenerator from "../classes/docblock-generator.js"
|
||||||
|
import getMonorepoRoot from "../utils/get-monorepo-root.js"
|
||||||
|
import promiseExec from "../utils/promise-exec.js"
|
||||||
|
import filterFiles from "../utils/filter-files.js"
|
||||||
|
|
||||||
|
export default async function runGitChanges() {
|
||||||
|
const monorepoPath = getMonorepoRoot()
|
||||||
|
// retrieve the changed files under `packages` in the monorepo root.
|
||||||
|
const childProcess = await promiseExec(
|
||||||
|
`git diff --name-only -- "packages/**/**.ts" "packages/**/*.js" "packages/**/*.tsx" "packages/**/*.jsx"`,
|
||||||
|
{
|
||||||
|
cwd: monorepoPath,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let files = filterFiles(
|
||||||
|
childProcess.stdout.toString().split("\n").filter(Boolean)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!files.length) {
|
||||||
|
console.log(`No file changes detected.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${files.length} files have changed. Running generator on them...`
|
||||||
|
)
|
||||||
|
|
||||||
|
files = files.map((filePath) => path.resolve(monorepoPath, filePath))
|
||||||
|
|
||||||
|
// generate docblocks for each of the files.
|
||||||
|
const docblockGenerator = new DocblockGenerator({
|
||||||
|
paths: files,
|
||||||
|
})
|
||||||
|
|
||||||
|
await docblockGenerator.run()
|
||||||
|
|
||||||
|
console.log(`Finished generating docs for ${files.length} files.`)
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Octokit } from "@octokit/core"
|
||||||
|
import filterFiles from "../utils/filter-files.js"
|
||||||
|
import path from "path"
|
||||||
|
import getMonorepoRoot from "../utils/get-monorepo-root.js"
|
||||||
|
import DocblockGenerator from "../classes/docblock-generator.js"
|
||||||
|
|
||||||
|
export default async function (commitSha: string) {
|
||||||
|
const monorepoPath = getMonorepoRoot()
|
||||||
|
// retrieve the files changed in the commit
|
||||||
|
const octokit = new Octokit({
|
||||||
|
auth: process.env.GH_TOKEN,
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { files },
|
||||||
|
} = await octokit.request("GET /repos/{owner}/{repo}/commits/{ref}", {
|
||||||
|
owner: "medusajs",
|
||||||
|
repo: "medusa",
|
||||||
|
ref: commitSha,
|
||||||
|
headers: {
|
||||||
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// filter changed files
|
||||||
|
let filteredFiles = filterFiles(files?.map((file) => file.filename) || [])
|
||||||
|
|
||||||
|
if (!filteredFiles.length) {
|
||||||
|
console.log("No applicable files changed. Canceling...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${filteredFiles.length} files have changed. Running generator on them...`
|
||||||
|
)
|
||||||
|
|
||||||
|
filteredFiles = filteredFiles.map((filePath) =>
|
||||||
|
path.resolve(monorepoPath, filePath)
|
||||||
|
)
|
||||||
|
|
||||||
|
// generate docblocks for each of the files.
|
||||||
|
const docblockGenerator = new DocblockGenerator({
|
||||||
|
paths: filteredFiles,
|
||||||
|
})
|
||||||
|
|
||||||
|
await docblockGenerator.run()
|
||||||
|
|
||||||
|
console.log(`Finished generating docs for ${filteredFiles.length} files.`)
|
||||||
|
}
|
||||||
17
docs-util/packages/docblock-generator/src/commands/run.ts
Normal file
17
docs-util/packages/docblock-generator/src/commands/run.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import DocblockGenerator, { Options } from "../classes/docblock-generator.js"
|
||||||
|
|
||||||
|
export default async function run(
|
||||||
|
paths: string[],
|
||||||
|
options: Omit<Options, "paths">
|
||||||
|
) {
|
||||||
|
console.log("Running...")
|
||||||
|
|
||||||
|
const docblockGenerator = new DocblockGenerator({
|
||||||
|
paths,
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
|
||||||
|
await docblockGenerator.run()
|
||||||
|
|
||||||
|
console.log(`Finished running.`)
|
||||||
|
}
|
||||||
4
docs-util/packages/docblock-generator/src/constants.ts
Normal file
4
docs-util/packages/docblock-generator/src/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const DOCBLOCK_NEW_LINE = "\n * "
|
||||||
|
export const DOCBLOCK_START = `*${DOCBLOCK_NEW_LINE}`
|
||||||
|
export const DOCBLOCK_END_LINE = "\n"
|
||||||
|
export const DOCBLOCK_DOUBLE_LINES = `${DOCBLOCK_NEW_LINE}${DOCBLOCK_NEW_LINE}`
|
||||||
33
docs-util/packages/docblock-generator/src/index.ts
Normal file
33
docs-util/packages/docblock-generator/src/index.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import "dotenv/config"
|
||||||
|
import { Command } from "commander"
|
||||||
|
import run from "./commands/run.js"
|
||||||
|
import runGitChanges from "./commands/run-git-changes.js"
|
||||||
|
import runGitCommit from "./commands/run-git-commit.js"
|
||||||
|
|
||||||
|
const program = new Command()
|
||||||
|
|
||||||
|
program.name("docblock-generator").description("Generate TSDoc doc-blocks")
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("run")
|
||||||
|
.description("Generate TSDoc doc-blocks for specified files.")
|
||||||
|
.argument("<files...>", "One or more TypeScript file or directory paths.")
|
||||||
|
.option(
|
||||||
|
"--dry-run",
|
||||||
|
"Whether to run the command without writing the changes."
|
||||||
|
)
|
||||||
|
.action(run)
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("run:changes")
|
||||||
|
.description("Generate TSDoc doc-blocks for changed files in git.")
|
||||||
|
.action(runGitChanges)
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("run:commit")
|
||||||
|
.description("Generate TSDoc doc-blocks for changed files in a commit.")
|
||||||
|
.argument("<commitSha>", "The SHA of a commit.")
|
||||||
|
.action(runGitCommit)
|
||||||
|
|
||||||
|
program.parse()
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import path from "path"
|
||||||
|
import { fileURLToPath } from "url"
|
||||||
|
|
||||||
|
export default function dirname() {
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
|
||||||
|
return path.dirname(__filename)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { minimatch } from "minimatch"
|
||||||
|
|
||||||
|
export default function (files: string[]): string[] {
|
||||||
|
return files.filter((file) =>
|
||||||
|
minimatch(
|
||||||
|
file,
|
||||||
|
"**/packages/@(medusa|types|medusa-js|medusa-react)/src/**/*.@(ts|tsx|js|jsx)",
|
||||||
|
{
|
||||||
|
matchBase: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import path from "path"
|
||||||
|
import dirname from "./dirname.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the monorepo root either from the `MONOREPO_ROOT_PATH` environment
|
||||||
|
* variable, or inferring it from the path.
|
||||||
|
*
|
||||||
|
* @returns {string} The absolute path to the monorepository.
|
||||||
|
*/
|
||||||
|
export default function getMonorepoRoot() {
|
||||||
|
return (
|
||||||
|
process.env.MONOREPO_ROOT_PATH ||
|
||||||
|
path.join(dirname(), "..", "..", "..", "..", "..")
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import path from "path"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get relative path of multiple file paths to a specified path.
|
||||||
|
*
|
||||||
|
* @param {string[]} filePaths - The file paths to retrieve their relative path.
|
||||||
|
* @param {string} pathPrefix - The path to retrieve paths relative to.
|
||||||
|
* @returns {string[]} The relative file paths.
|
||||||
|
*/
|
||||||
|
export default function getRelativePaths(
|
||||||
|
filePaths: string[],
|
||||||
|
pathPrefix: string
|
||||||
|
): string[] {
|
||||||
|
return filePaths.map((filePath) => path.resolve(pathPrefix, filePath))
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the symbol of a node.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to retrieve its symbol.
|
||||||
|
* @param {ts.TypeChecker} checker - The type checker of the TypeScript program the symbol is in.
|
||||||
|
* @returns {ts.Symbol | undefined} The symbol if found.
|
||||||
|
*/
|
||||||
|
export default function getSymbol(
|
||||||
|
node: ts.Node,
|
||||||
|
checker: ts.TypeChecker
|
||||||
|
): ts.Symbol | undefined {
|
||||||
|
if (
|
||||||
|
ts.isVariableStatement(node) &&
|
||||||
|
node.declarationList.declarations.length
|
||||||
|
) {
|
||||||
|
return getSymbol(node.declarationList.declarations[0], checker)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "symbol" in node && node.symbol
|
||||||
|
? (node.symbol as ts.Symbol)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import path from "path"
|
||||||
|
import getMonorepoRoot from "./get-monorepo-root.js"
|
||||||
|
import ts from "typescript"
|
||||||
|
import { minimatch } from "minimatch"
|
||||||
|
import { capitalize } from "./str-formatting.js"
|
||||||
|
|
||||||
|
export const kindsCanHaveNamespace = [
|
||||||
|
ts.SyntaxKind.SourceFile,
|
||||||
|
ts.SyntaxKind.ClassDeclaration,
|
||||||
|
ts.SyntaxKind.EnumDeclaration,
|
||||||
|
ts.SyntaxKind.ModuleDeclaration,
|
||||||
|
ts.SyntaxKind.InterfaceDeclaration,
|
||||||
|
ts.SyntaxKind.TypeAliasDeclaration,
|
||||||
|
ts.SyntaxKind.MethodDeclaration,
|
||||||
|
ts.SyntaxKind.MethodSignature,
|
||||||
|
ts.SyntaxKind.FunctionDeclaration,
|
||||||
|
ts.SyntaxKind.ArrowFunction,
|
||||||
|
ts.SyntaxKind.VariableStatement,
|
||||||
|
]
|
||||||
|
|
||||||
|
export const pathsHavingCustomNamespace = [
|
||||||
|
"**/packages/medusa\\-react/src/hooks/**/index.ts",
|
||||||
|
"**/packages/medusa\\-react/src/@(helpers|contexts)/**/*.@(tsx|ts)",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const CUSTOM_NAMESPACE_TAG = "@customNamespace"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path used with the {@link CUSTOM_NAMESPACE_TAG}.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to retrieve its custom namespace path.
|
||||||
|
* @returns {string} The namespace path.
|
||||||
|
*/
|
||||||
|
export function getNamespacePath(node: ts.Node): string {
|
||||||
|
const packagePathPrefix = `${path.resolve(
|
||||||
|
getMonorepoRoot(),
|
||||||
|
"packages/medusa-react/src"
|
||||||
|
)}/`
|
||||||
|
|
||||||
|
const sourceFile = node.getSourceFile()
|
||||||
|
|
||||||
|
let hookPath = path
|
||||||
|
.dirname(sourceFile.fileName)
|
||||||
|
.replace(packagePathPrefix, "")
|
||||||
|
|
||||||
|
const fileName = path.basename(sourceFile.fileName)
|
||||||
|
|
||||||
|
if (
|
||||||
|
!fileName.startsWith("index") &&
|
||||||
|
!fileName.startsWith("mutations") &&
|
||||||
|
!fileName.startsWith("queries")
|
||||||
|
) {
|
||||||
|
hookPath += `/${fileName.replace(path.extname(fileName), "")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return hookPath
|
||||||
|
.split("/")
|
||||||
|
.map((pathItem, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
pathItem = pathItem
|
||||||
|
.replace("contexts", "providers")
|
||||||
|
.replace("helpers", "utilities")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathItem
|
||||||
|
.split("-")
|
||||||
|
.map((item) => capitalize(item))
|
||||||
|
.join(" ")
|
||||||
|
})
|
||||||
|
.join(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the full tag of the custom namespace with its value.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to retrieve its custom namespace path.
|
||||||
|
* @returns {string} The custom namespace tag and value.
|
||||||
|
*/
|
||||||
|
export function getCustomNamespaceTag(node: ts.Node): string {
|
||||||
|
return `${CUSTOM_NAMESPACE_TAG} ${getNamespacePath(node)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node should have a custom namespace path.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the node should have a custom namespace.
|
||||||
|
*/
|
||||||
|
export function shouldHaveCustomNamespace(node: ts.Node): boolean {
|
||||||
|
if (!kindsCanHaveNamespace.includes(node.kind)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = node.getSourceFile().fileName
|
||||||
|
|
||||||
|
return pathsHavingCustomNamespace.some((pattern) =>
|
||||||
|
minimatch(fileName, pattern, {
|
||||||
|
matchBase: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import ts from "typescript"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a node has comments.
|
||||||
|
*
|
||||||
|
* @param {ts.Node} node - The node to check.
|
||||||
|
* @returns {boolean} Whether the node has comments.
|
||||||
|
*/
|
||||||
|
export default function nodeHasComments(node: ts.Node): boolean {
|
||||||
|
return (
|
||||||
|
ts.getLeadingCommentRanges(
|
||||||
|
node.getSourceFile().getFullText(),
|
||||||
|
node.getFullStart()
|
||||||
|
) !== undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import util from "node:util"
|
||||||
|
import { exec } from "child_process"
|
||||||
|
|
||||||
|
export default util.promisify(exec)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export function capitalize(str: string): string {
|
||||||
|
return `${str.charAt(0).toUpperCase()}${str.substring(1).toLowerCase()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function camelToWords(str: string): string {
|
||||||
|
return str
|
||||||
|
.replaceAll(/([A-Z])/g, " $1")
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function camelToTitle(str: string): string {
|
||||||
|
return str
|
||||||
|
.replaceAll(/([A-Z])/g, " $1")
|
||||||
|
.split(" ")
|
||||||
|
.map((word) => capitalize(word))
|
||||||
|
.join(" ")
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function snakeToWords(str: string): string {
|
||||||
|
return str.replaceAll("_", " ").toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove parts of the name such as DTO, Filterable, etc...
|
||||||
|
*
|
||||||
|
* @param {string} str - The name to format.
|
||||||
|
* @returns {string} The normalized name.
|
||||||
|
*/
|
||||||
|
export function normalizeName(str: string): string {
|
||||||
|
return str
|
||||||
|
.replace(/^(create|update|delete)/i, "")
|
||||||
|
.replace(/DTO$/, "")
|
||||||
|
.replace(/^Filterable/, "")
|
||||||
|
.replace(/Props$/, "")
|
||||||
|
}
|
||||||
20
docs-util/packages/docblock-generator/tsconfig.json
Normal file
20
docs-util/packages/docblock-generator/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleResolution": "node16",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"ts-node": {
|
||||||
|
"esm": true,
|
||||||
|
"experimentalSpecifierResolution": "node",
|
||||||
|
"transpileOnly": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -419,6 +419,23 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@eslint/eslintrc@npm:^2.1.4":
|
||||||
|
version: 2.1.4
|
||||||
|
resolution: "@eslint/eslintrc@npm:2.1.4"
|
||||||
|
dependencies:
|
||||||
|
ajv: ^6.12.4
|
||||||
|
debug: ^4.3.2
|
||||||
|
espree: ^9.6.0
|
||||||
|
globals: ^13.19.0
|
||||||
|
ignore: ^5.2.0
|
||||||
|
import-fresh: ^3.2.1
|
||||||
|
js-yaml: ^4.1.0
|
||||||
|
minimatch: ^3.1.2
|
||||||
|
strip-json-comments: ^3.1.1
|
||||||
|
checksum: 32f67052b81768ae876c84569ffd562491ec5a5091b0c1e1ca1e0f3c24fb42f804952fdd0a137873bc64303ba368a71ba079a6f691cee25beee9722d94cc8573
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@eslint/js@npm:8.54.0":
|
"@eslint/js@npm:8.54.0":
|
||||||
version: 8.54.0
|
version: 8.54.0
|
||||||
resolution: "@eslint/js@npm:8.54.0"
|
resolution: "@eslint/js@npm:8.54.0"
|
||||||
@@ -426,6 +443,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@eslint/js@npm:8.56.0":
|
||||||
|
version: 8.56.0
|
||||||
|
resolution: "@eslint/js@npm:8.56.0"
|
||||||
|
checksum: 60b3a1cf240e2479cec9742424224465dc50e46d781da1b7f5ef240501b2d1202c225bd456207faac4b34a64f4765833345bc4ddffd00395e1db40fa8c426f5a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@fastify/busboy@npm:^2.0.0":
|
"@fastify/busboy@npm:^2.0.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "@fastify/busboy@npm:2.1.0"
|
resolution: "@fastify/busboy@npm:2.1.0"
|
||||||
@@ -825,6 +849,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/auth-token@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "@octokit/auth-token@npm:4.0.0"
|
||||||
|
checksum: 57acaa6c394c5abab2f74e8e1dcf4e7a16b236f713c77a54b8f08e2d14114de94b37946259e33ec2aab0566b26f724c2b71d2602352b59e541a9854897618f3c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/core@npm:^4.0.5":
|
"@octokit/core@npm:^4.0.5":
|
||||||
version: 4.2.4
|
version: 4.2.4
|
||||||
resolution: "@octokit/core@npm:4.2.4"
|
resolution: "@octokit/core@npm:4.2.4"
|
||||||
@@ -840,6 +871,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/core@npm:^5.0.2":
|
||||||
|
version: 5.0.2
|
||||||
|
resolution: "@octokit/core@npm:5.0.2"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/auth-token": ^4.0.0
|
||||||
|
"@octokit/graphql": ^7.0.0
|
||||||
|
"@octokit/request": ^8.0.2
|
||||||
|
"@octokit/request-error": ^5.0.0
|
||||||
|
"@octokit/types": ^12.0.0
|
||||||
|
before-after-hook: ^2.2.0
|
||||||
|
universal-user-agent: ^6.0.0
|
||||||
|
checksum: f3b3cb72f8f374e763e60922eacad56cb08fc05ee0be26f2a7b61937f89a377a8fd1b54f3d621a2b9627a9402c595d4b7e24900602e401b8a8edaffd995fa98f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/endpoint@npm:^7.0.0":
|
"@octokit/endpoint@npm:^7.0.0":
|
||||||
version: 7.0.6
|
version: 7.0.6
|
||||||
resolution: "@octokit/endpoint@npm:7.0.6"
|
resolution: "@octokit/endpoint@npm:7.0.6"
|
||||||
@@ -851,6 +897,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/endpoint@npm:^9.0.0":
|
||||||
|
version: 9.0.4
|
||||||
|
resolution: "@octokit/endpoint@npm:9.0.4"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/types": ^12.0.0
|
||||||
|
universal-user-agent: ^6.0.0
|
||||||
|
checksum: f1c857c5d85afa9d7e8857f7f97dbec28d3b6ab1dc21fe35172f1bc9e5512c8a3a26edabf6b2d83bb60d700f7ad290c96be960496aa83606095630edfad06db4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/graphql@npm:^5.0.0":
|
"@octokit/graphql@npm:^5.0.0":
|
||||||
version: 5.0.6
|
version: 5.0.6
|
||||||
resolution: "@octokit/graphql@npm:5.0.6"
|
resolution: "@octokit/graphql@npm:5.0.6"
|
||||||
@@ -862,6 +918,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/graphql@npm:^7.0.0":
|
||||||
|
version: 7.0.2
|
||||||
|
resolution: "@octokit/graphql@npm:7.0.2"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/request": ^8.0.1
|
||||||
|
"@octokit/types": ^12.0.0
|
||||||
|
universal-user-agent: ^6.0.0
|
||||||
|
checksum: 96e5d6b970be60877134cc147b9249534f3a79d691b9932d731d453426fa1e1a0a36111a1b0a6ab43d61309c630903a65db5559b5c800300dc26cf588f50fea8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/openapi-types@npm:^18.0.0":
|
"@octokit/openapi-types@npm:^18.0.0":
|
||||||
version: 18.1.1
|
version: 18.1.1
|
||||||
resolution: "@octokit/openapi-types@npm:18.1.1"
|
resolution: "@octokit/openapi-types@npm:18.1.1"
|
||||||
@@ -869,6 +936,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/openapi-types@npm:^19.1.0":
|
||||||
|
version: 19.1.0
|
||||||
|
resolution: "@octokit/openapi-types@npm:19.1.0"
|
||||||
|
checksum: ae8081f52b797b91a12d4f6cddc475699c9d34b06645b337adc77d30b583d8fe8506597a45c42f8f1a96bfb2a9d092cee257d8a65d718bfeed23a0d153448eea
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/request-error@npm:^3.0.0":
|
"@octokit/request-error@npm:^3.0.0":
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
resolution: "@octokit/request-error@npm:3.0.3"
|
resolution: "@octokit/request-error@npm:3.0.3"
|
||||||
@@ -880,6 +954,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/request-error@npm:^5.0.0":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "@octokit/request-error@npm:5.0.1"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/types": ^12.0.0
|
||||||
|
deprecation: ^2.0.0
|
||||||
|
once: ^1.4.0
|
||||||
|
checksum: e72a4627120de345b54876a1f007664095e5be9d624fce2e14fccf7668cd8f5e4929d444d8fc085d48e1fb5cd548538453974aab129a669101110d6679dce6c6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/request@npm:^6.0.0":
|
"@octokit/request@npm:^6.0.0":
|
||||||
version: 6.2.8
|
version: 6.2.8
|
||||||
resolution: "@octokit/request@npm:6.2.8"
|
resolution: "@octokit/request@npm:6.2.8"
|
||||||
@@ -894,6 +979,27 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/request@npm:^8.0.1, @octokit/request@npm:^8.0.2":
|
||||||
|
version: 8.1.6
|
||||||
|
resolution: "@octokit/request@npm:8.1.6"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/endpoint": ^9.0.0
|
||||||
|
"@octokit/request-error": ^5.0.0
|
||||||
|
"@octokit/types": ^12.0.0
|
||||||
|
universal-user-agent: ^6.0.0
|
||||||
|
checksum: ef84418e0b1f28335c105bca2b1518b04797791761024d26f80f60a528cdcf468baf9897fd34f535c42af0643a598884f882bc832e68edbfe1ea530c2df563a4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@octokit/types@npm:^12.0.0":
|
||||||
|
version: 12.4.0
|
||||||
|
resolution: "@octokit/types@npm:12.4.0"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/openapi-types": ^19.1.0
|
||||||
|
checksum: b52b3fd8af307a1868846991f8376548a790814b20639dee1110271a768c0489081970df893ca2230f6285066003230d22f5877eeac90418971a475c79808241
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@octokit/types@npm:^9.0.0":
|
"@octokit/types@npm:^9.0.0":
|
||||||
version: 9.3.2
|
version: 9.3.2
|
||||||
resolution: "@octokit/types@npm:9.3.2"
|
resolution: "@octokit/types@npm:9.3.2"
|
||||||
@@ -1826,6 +1932,23 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"docblock-generator@workspace:packages/docblock-generator":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "docblock-generator@workspace:packages/docblock-generator"
|
||||||
|
dependencies:
|
||||||
|
"@octokit/core": ^5.0.2
|
||||||
|
"@types/node": ^20.9.4
|
||||||
|
commander: ^11.1.0
|
||||||
|
dotenv: ^16.3.1
|
||||||
|
eslint: ^8.56.0
|
||||||
|
minimatch: ^9.0.3
|
||||||
|
ts-node: ^10.9.1
|
||||||
|
typescript: 5.2
|
||||||
|
bin:
|
||||||
|
workflow-diagrams-generator: dist/index.js
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"docs-util@workspace:.":
|
"docs-util@workspace:.":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "docs-util@workspace:."
|
resolution: "docs-util@workspace:."
|
||||||
@@ -1858,6 +1981,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"dotenv@npm:^16.3.1":
|
||||||
|
version: 16.3.1
|
||||||
|
resolution: "dotenv@npm:16.3.1"
|
||||||
|
checksum: b95ff1bbe624ead85a3cd70dbd827e8e06d5f05f716f2d0cbc476532d54c7c9469c3bc4dd93ea519f6ad711cb522c00ac9a62b6eb340d5affae8008facc3fbd7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"dset@npm:^3.1.2":
|
"dset@npm:^3.1.2":
|
||||||
version: 3.1.3
|
version: 3.1.3
|
||||||
resolution: "dset@npm:3.1.3"
|
resolution: "dset@npm:3.1.3"
|
||||||
@@ -2051,6 +2181,54 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"eslint@npm:^8.56.0":
|
||||||
|
version: 8.56.0
|
||||||
|
resolution: "eslint@npm:8.56.0"
|
||||||
|
dependencies:
|
||||||
|
"@eslint-community/eslint-utils": ^4.2.0
|
||||||
|
"@eslint-community/regexpp": ^4.6.1
|
||||||
|
"@eslint/eslintrc": ^2.1.4
|
||||||
|
"@eslint/js": 8.56.0
|
||||||
|
"@humanwhocodes/config-array": ^0.11.13
|
||||||
|
"@humanwhocodes/module-importer": ^1.0.1
|
||||||
|
"@nodelib/fs.walk": ^1.2.8
|
||||||
|
"@ungap/structured-clone": ^1.2.0
|
||||||
|
ajv: ^6.12.4
|
||||||
|
chalk: ^4.0.0
|
||||||
|
cross-spawn: ^7.0.2
|
||||||
|
debug: ^4.3.2
|
||||||
|
doctrine: ^3.0.0
|
||||||
|
escape-string-regexp: ^4.0.0
|
||||||
|
eslint-scope: ^7.2.2
|
||||||
|
eslint-visitor-keys: ^3.4.3
|
||||||
|
espree: ^9.6.1
|
||||||
|
esquery: ^1.4.2
|
||||||
|
esutils: ^2.0.2
|
||||||
|
fast-deep-equal: ^3.1.3
|
||||||
|
file-entry-cache: ^6.0.1
|
||||||
|
find-up: ^5.0.0
|
||||||
|
glob-parent: ^6.0.2
|
||||||
|
globals: ^13.19.0
|
||||||
|
graphemer: ^1.4.0
|
||||||
|
ignore: ^5.2.0
|
||||||
|
imurmurhash: ^0.1.4
|
||||||
|
is-glob: ^4.0.0
|
||||||
|
is-path-inside: ^3.0.3
|
||||||
|
js-yaml: ^4.1.0
|
||||||
|
json-stable-stringify-without-jsonify: ^1.0.1
|
||||||
|
levn: ^0.4.1
|
||||||
|
lodash.merge: ^4.6.2
|
||||||
|
minimatch: ^3.1.2
|
||||||
|
natural-compare: ^1.4.0
|
||||||
|
optionator: ^0.9.3
|
||||||
|
strip-ansi: ^6.0.1
|
||||||
|
text-table: ^0.2.0
|
||||||
|
bin:
|
||||||
|
eslint: bin/eslint.js
|
||||||
|
checksum: 2be598f7da1339d045ad933ffd3d4742bee610515cd2b0d9a2b8b729395a01d4e913552fff555b559fccaefd89d7b37632825789d1b06470608737ae69ab43fb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"esm@npm:^3.2.25":
|
"esm@npm:^3.2.25":
|
||||||
version: 3.2.25
|
version: 3.2.25
|
||||||
resolution: "esm@npm:3.2.25"
|
resolution: "esm@npm:3.2.25"
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
"@babel/preset-react": "^7.18.6",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/register": "^7.11.5",
|
"@babel/register": "^7.11.5",
|
||||||
"@babel/runtime": "^7.11.2",
|
"@babel/runtime": "^7.11.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||||
"@typescript-eslint/parser": "^5.53.0",
|
"@typescript-eslint/parser": "^6.19.0",
|
||||||
"axios": "^0.21.4",
|
"axios": "^0.21.4",
|
||||||
"axios-mock-adapter": "^1.19.0",
|
"axios-mock-adapter": "^1.19.0",
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
"hooks:uninstall": "husky uninstall",
|
"hooks:uninstall": "husky uninstall",
|
||||||
"build": "turbo run build --concurrency=50% --no-daemon",
|
"build": "turbo run build --concurrency=50% --no-daemon",
|
||||||
"lint": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx .",
|
"lint": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx .",
|
||||||
|
"lint:path": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx",
|
||||||
"prettier": "prettier",
|
"prettier": "prettier",
|
||||||
"jest": "jest",
|
"jest": "jest",
|
||||||
"test": "turbo run test --concurrency=50% --no-daemon",
|
"test": "turbo run test --concurrency=50% --no-daemon",
|
||||||
|
|||||||
@@ -41,8 +41,8 @@
|
|||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.1",
|
||||||
"@types/validator": "^13.7.17",
|
"@types/validator": "^13.7.17",
|
||||||
"@types/wait-on": "^5.3.1",
|
"@types/wait-on": "^5.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.5",
|
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||||
"@typescript-eslint/parser": "^5.59.5",
|
"@typescript-eslint/parser": "^6.19.0",
|
||||||
"configstore": "^6.0.0",
|
"configstore": "^6.0.0",
|
||||||
"eslint": "^8.40.0",
|
"eslint": "^8.40.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ import { adminAuthKeys } from "./queries"
|
|||||||
* @category Mutations
|
* @category Mutations
|
||||||
*/
|
*/
|
||||||
export const useAdminLogin = (
|
export const useAdminLogin = (
|
||||||
/**
|
|
||||||
* stuff again
|
|
||||||
*/
|
|
||||||
options?: UseMutationOptions<Response<AdminAuthRes>, Error, AdminPostAuthReq>
|
options?: UseMutationOptions<Response<AdminAuthRes>, Error, AdminPostAuthReq>
|
||||||
) => {
|
) => {
|
||||||
const { client } = useMedusa()
|
const { client } = useMedusa()
|
||||||
|
|||||||
@@ -110,8 +110,6 @@ export const useAdminCancelBatchJob = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reactMutationHook
|
|
||||||
*
|
|
||||||
* When a batch job is created, it's not executed automatically if `dry_run` is set to `true`. This hook confirms that the batch job should be executed.
|
* When a batch job is created, it's not executed automatically if `dry_run` is set to `true`. This hook confirms that the batch job should be executed.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { EntityManager } from "typeorm"
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface
|
* @interface
|
||||||
*
|
*
|
||||||
* A shared context object that is used to share resources between the application and the module.
|
* A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
*/
|
*/
|
||||||
export type SharedContext = {
|
export type SharedContext = {
|
||||||
/**
|
/**
|
||||||
@@ -18,8 +18,8 @@ export type SharedContext = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface
|
* @interface
|
||||||
*
|
*
|
||||||
* A shared context object that is used to share resources between the application and the module.
|
* A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
*/
|
*/
|
||||||
export type Context<TManager = unknown> = {
|
export type Context<TManager = unknown> = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
229
yarn.lock
229
yarn.lock
@@ -5579,7 +5579,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@npm:^4.2.0":
|
"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0":
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
resolution: "@eslint-community/eslint-utils@npm:4.4.0"
|
resolution: "@eslint-community/eslint-utils@npm:4.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5597,6 +5597,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@eslint-community/regexpp@npm:^4.5.1":
|
||||||
|
version: 4.10.0
|
||||||
|
resolution: "@eslint-community/regexpp@npm:4.10.0"
|
||||||
|
checksum: c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@eslint/eslintrc@npm:^0.4.3":
|
"@eslint/eslintrc@npm:^0.4.3":
|
||||||
version: 0.4.3
|
version: 0.4.3
|
||||||
resolution: "@eslint/eslintrc@npm:0.4.3"
|
resolution: "@eslint/eslintrc@npm:0.4.3"
|
||||||
@@ -17422,6 +17429,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/json-schema@npm:^7.0.12":
|
||||||
|
version: 7.0.15
|
||||||
|
resolution: "@types/json-schema@npm:7.0.15"
|
||||||
|
checksum: a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/json5@npm:^0.0.29":
|
"@types/json5@npm:^0.0.29":
|
||||||
version: 0.0.29
|
version: 0.0.29
|
||||||
resolution: "@types/json5@npm:0.0.29"
|
resolution: "@types/json5@npm:0.0.29"
|
||||||
@@ -18264,27 +18278,28 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@npm:^5.53.0, @typescript-eslint/eslint-plugin@npm:^5.59.5":
|
"@typescript-eslint/eslint-plugin@npm:^6.19.0":
|
||||||
version: 5.60.1
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/eslint-plugin@npm:5.60.1"
|
resolution: "@typescript-eslint/eslint-plugin@npm:6.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/regexpp": ^4.4.0
|
"@eslint-community/regexpp": ^4.5.1
|
||||||
"@typescript-eslint/scope-manager": 5.60.1
|
"@typescript-eslint/scope-manager": 6.19.0
|
||||||
"@typescript-eslint/type-utils": 5.60.1
|
"@typescript-eslint/type-utils": 6.19.0
|
||||||
"@typescript-eslint/utils": 5.60.1
|
"@typescript-eslint/utils": 6.19.0
|
||||||
|
"@typescript-eslint/visitor-keys": 6.19.0
|
||||||
debug: ^4.3.4
|
debug: ^4.3.4
|
||||||
grapheme-splitter: ^1.0.4
|
graphemer: ^1.4.0
|
||||||
ignore: ^5.2.0
|
ignore: ^5.2.4
|
||||||
natural-compare-lite: ^1.4.0
|
natural-compare: ^1.4.0
|
||||||
semver: ^7.3.7
|
semver: ^7.5.4
|
||||||
tsutils: ^3.21.0
|
ts-api-utils: ^1.0.1
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@typescript-eslint/parser": ^5.0.0
|
"@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 1861e7fde48019ecae9acbc654d24f746e6a375f11f6f924e2ff3c9aa52528744a003da14592fafdbc407cf58b8cf7d0e42c624f3de06cb7bee5d8a31879ed79
|
checksum: ab1a5ace6663b0c6d2418e321328fa28aa4bdc4b5fae257addec01346fb3a9c2d3a2960ade0f7114e6974c513a28632c9e8e602333cc0fab3135c445babdef59
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -18321,20 +18336,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/parser@npm:^5.53.0, @typescript-eslint/parser@npm:^5.59.5":
|
"@typescript-eslint/parser@npm:^6.19.0":
|
||||||
version: 5.60.1
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/parser@npm:5.60.1"
|
resolution: "@typescript-eslint/parser@npm:6.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager": 5.60.1
|
"@typescript-eslint/scope-manager": 6.19.0
|
||||||
"@typescript-eslint/types": 5.60.1
|
"@typescript-eslint/types": 6.19.0
|
||||||
"@typescript-eslint/typescript-estree": 5.60.1
|
"@typescript-eslint/typescript-estree": 6.19.0
|
||||||
|
"@typescript-eslint/visitor-keys": 6.19.0
|
||||||
debug: ^4.3.4
|
debug: ^4.3.4
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: b44d041bb46908078df898ab1d8a0da0a58901caced0bb657af9d48c6bb54c090e565cc31d7526a27f25faeb25315fdec648873b2527feed043532a053914dd2
|
checksum: d547bfb1aaed112cfc0f9f0be8506a280952ba3b61be42b749352139361bd94e4a47fa043d819e19c6a498cacbd8bb36a46e3628c436a7e2009e7ac27afc8861
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -18348,16 +18364,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@npm:5.60.1":
|
|
||||||
version: 5.60.1
|
|
||||||
resolution: "@typescript-eslint/scope-manager@npm:5.60.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": 5.60.1
|
|
||||||
"@typescript-eslint/visitor-keys": 5.60.1
|
|
||||||
checksum: 50164675adb4850354a8e0297d498b59283eee961e10e0c00f9d664e03b464a9de4dc7a9d84c534c84df6ac3ea6f32238e2df9528374104bd66678b1ec9fbfec
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@npm:5.62.0":
|
"@typescript-eslint/scope-manager@npm:5.62.0":
|
||||||
version: 5.62.0
|
version: 5.62.0
|
||||||
resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
|
resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
|
||||||
@@ -18368,20 +18374,30 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@npm:5.60.1":
|
"@typescript-eslint/scope-manager@npm:6.19.0":
|
||||||
version: 5.60.1
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/type-utils@npm:5.60.1"
|
resolution: "@typescript-eslint/scope-manager@npm:6.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/typescript-estree": 5.60.1
|
"@typescript-eslint/types": 6.19.0
|
||||||
"@typescript-eslint/utils": 5.60.1
|
"@typescript-eslint/visitor-keys": 6.19.0
|
||||||
|
checksum: 1ec7b9dedca7975f0aa4543c1c382f7d6131411bd443a5f9b96f137acb6adb450888ed13c95f6d26546b682b2e0579ce8a1c883fdbe2255dc0b61052193b8243
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@typescript-eslint/type-utils@npm:6.19.0":
|
||||||
|
version: 6.19.0
|
||||||
|
resolution: "@typescript-eslint/type-utils@npm:6.19.0"
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/typescript-estree": 6.19.0
|
||||||
|
"@typescript-eslint/utils": 6.19.0
|
||||||
debug: ^4.3.4
|
debug: ^4.3.4
|
||||||
tsutils: ^3.21.0
|
ts-api-utils: ^1.0.1
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: "*"
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: ef07f5c84636b8a9ff68dbc093ba6bce32d0e0f56831b214c2df3ff189502ae103c73bda7eb5e9f9ca21d3492dc851b7ac4b2cb83bdd6fbf5a9fe21068b404f4
|
checksum: 5b146b985481e587122026c703ac9f537ad7e90eee1dca814971bca0d7e4a5d4ff9861fb4bf749014c28c6a4fbb4a01a4527355961315eb9501f3569f8e8dd38
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -18392,13 +18408,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/types@npm:5.60.1":
|
|
||||||
version: 5.60.1
|
|
||||||
resolution: "@typescript-eslint/types@npm:5.60.1"
|
|
||||||
checksum: 4be7654356f9b79fb942ae22196b518f30e20b07588355df22c85dfdcdaafe02f312b473de67af34fbb2283182d0d337aa65312f1117c6f8bf635cc427944c23
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/types@npm:5.62.0":
|
"@typescript-eslint/types@npm:5.62.0":
|
||||||
version: 5.62.0
|
version: 5.62.0
|
||||||
resolution: "@typescript-eslint/types@npm:5.62.0"
|
resolution: "@typescript-eslint/types@npm:5.62.0"
|
||||||
@@ -18406,6 +18415,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@typescript-eslint/types@npm:6.19.0":
|
||||||
|
version: 6.19.0
|
||||||
|
resolution: "@typescript-eslint/types@npm:6.19.0"
|
||||||
|
checksum: 6f81860a3c14df55232c2e6dec21fb166867b9f30b3c3369b325aef5ee1c7e41e827c0504654daa49c8ff1a3a9ca9d9bfe76786882b6212a7c1b58991a9c80b9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:4.33.0":
|
"@typescript-eslint/typescript-estree@npm:4.33.0":
|
||||||
version: 4.33.0
|
version: 4.33.0
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:4.33.0"
|
resolution: "@typescript-eslint/typescript-estree@npm:4.33.0"
|
||||||
@@ -18424,24 +18440,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:5.60.1":
|
|
||||||
version: 5.60.1
|
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:5.60.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": 5.60.1
|
|
||||||
"@typescript-eslint/visitor-keys": 5.60.1
|
|
||||||
debug: ^4.3.4
|
|
||||||
globby: ^11.1.0
|
|
||||||
is-glob: ^4.0.3
|
|
||||||
semver: ^7.3.7
|
|
||||||
tsutils: ^3.21.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
typescript:
|
|
||||||
optional: true
|
|
||||||
checksum: 09933d3c1b1bacf7e043d33a7e134489650fca7b7b965b633a1c526453f20478b38c4aa9b7c6da269d2a43f26608110d4c129eec917c4561431149dae82c3b9d
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:5.62.0":
|
"@typescript-eslint/typescript-estree@npm:5.62.0":
|
||||||
version: 5.62.0
|
version: 5.62.0
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
|
resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
|
||||||
@@ -18460,21 +18458,39 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/utils@npm:5.60.1":
|
"@typescript-eslint/typescript-estree@npm:6.19.0":
|
||||||
version: 5.60.1
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/utils@npm:5.60.1"
|
resolution: "@typescript-eslint/typescript-estree@npm:6.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils": ^4.2.0
|
"@typescript-eslint/types": 6.19.0
|
||||||
"@types/json-schema": ^7.0.9
|
"@typescript-eslint/visitor-keys": 6.19.0
|
||||||
"@types/semver": ^7.3.12
|
debug: ^4.3.4
|
||||||
"@typescript-eslint/scope-manager": 5.60.1
|
globby: ^11.1.0
|
||||||
"@typescript-eslint/types": 5.60.1
|
is-glob: ^4.0.3
|
||||||
"@typescript-eslint/typescript-estree": 5.60.1
|
minimatch: 9.0.3
|
||||||
eslint-scope: ^5.1.1
|
semver: ^7.5.4
|
||||||
semver: ^7.3.7
|
ts-api-utils: ^1.0.1
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
checksum: 5b365f009e43c7beafdbb7d8ecad78ee1087b0a4338cd9ec695eed514b7b4c1089e56239761139ddae629ec0ce8d428840c6ebfeea3618d2efe00c84f8794da5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@typescript-eslint/utils@npm:6.19.0":
|
||||||
|
version: 6.19.0
|
||||||
|
resolution: "@typescript-eslint/utils@npm:6.19.0"
|
||||||
|
dependencies:
|
||||||
|
"@eslint-community/eslint-utils": ^4.4.0
|
||||||
|
"@types/json-schema": ^7.0.12
|
||||||
|
"@types/semver": ^7.5.0
|
||||||
|
"@typescript-eslint/scope-manager": 6.19.0
|
||||||
|
"@typescript-eslint/types": 6.19.0
|
||||||
|
"@typescript-eslint/typescript-estree": 6.19.0
|
||||||
|
semver: ^7.5.4
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
checksum: cb408bd67dd5be3a3585b67ac19f60e9feb309a56782924b314077f7dc77cb10e690fdb4a7ac643784e8fab30bc04d6f23935c1aed6d08233f8dd8604782ac27
|
checksum: 343ff4cd4f7e102df8c46b41254d017a33d95df76455531fda679fdb92aebb9c111df8ee9ab54972e73c1e8fad9dd7e421001233f0aee8115384462b0821852e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -18506,16 +18522,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@npm:5.60.1":
|
|
||||||
version: 5.60.1
|
|
||||||
resolution: "@typescript-eslint/visitor-keys@npm:5.60.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": 5.60.1
|
|
||||||
eslint-visitor-keys: ^3.3.0
|
|
||||||
checksum: e70bd584ff0eef1c8739e3457e7402485acc06aba468ff8f191f4546aaed93ec91f309bb567a3d8bbd9a4aec030f3b73c8e8df085bb82cbb8ea9a0209c7355f8
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@npm:5.62.0":
|
"@typescript-eslint/visitor-keys@npm:5.62.0":
|
||||||
version: 5.62.0
|
version: 5.62.0
|
||||||
resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
|
resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
|
||||||
@@ -18526,6 +18532,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@typescript-eslint/visitor-keys@npm:6.19.0":
|
||||||
|
version: 6.19.0
|
||||||
|
resolution: "@typescript-eslint/visitor-keys@npm:6.19.0"
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/types": 6.19.0
|
||||||
|
eslint-visitor-keys: ^3.4.1
|
||||||
|
checksum: bb34e922e018aadf34866995ea5949d6623f184cc4f6470ab05767dd208ffabb003b7dc3872199714574b7f10afe89d49c6f89a4e8d086edea82be73e189f1bb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@uiw/react-json-view@npm:2.0.0-alpha.10":
|
"@uiw/react-json-view@npm:2.0.0-alpha.10":
|
||||||
version: 2.0.0-alpha.10
|
version: 2.0.0-alpha.10
|
||||||
resolution: "@uiw/react-json-view@npm:2.0.0-alpha.10"
|
resolution: "@uiw/react-json-view@npm:2.0.0-alpha.10"
|
||||||
@@ -23822,8 +23838,8 @@ __metadata:
|
|||||||
"@types/uuid": ^9.0.1
|
"@types/uuid": ^9.0.1
|
||||||
"@types/validator": ^13.7.17
|
"@types/validator": ^13.7.17
|
||||||
"@types/wait-on": ^5.3.1
|
"@types/wait-on": ^5.3.1
|
||||||
"@typescript-eslint/eslint-plugin": ^5.59.5
|
"@typescript-eslint/eslint-plugin": ^6.19.0
|
||||||
"@typescript-eslint/parser": ^5.59.5
|
"@typescript-eslint/parser": ^6.19.0
|
||||||
boxen: ^5
|
boxen: ^5
|
||||||
chalk: ^5.2.0
|
chalk: ^5.2.0
|
||||||
commander: ^10.0.1
|
commander: ^10.0.1
|
||||||
@@ -38265,6 +38281,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"minimatch@npm:9.0.3":
|
||||||
|
version: 9.0.3
|
||||||
|
resolution: "minimatch@npm:9.0.3"
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: ^2.0.1
|
||||||
|
checksum: 85f407dcd38ac3e180f425e86553911d101455ca3ad5544d6a7cec16286657e4f8a9aa6695803025c55e31e35a91a2252b5dc8e7d527211278b8b65b4dbd5eac
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"minimatch@npm:^5.0.1":
|
"minimatch@npm:^5.0.1":
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
resolution: "minimatch@npm:5.1.6"
|
resolution: "minimatch@npm:5.1.6"
|
||||||
@@ -38890,13 +38915,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"natural-compare-lite@npm:^1.4.0":
|
|
||||||
version: 1.4.0
|
|
||||||
resolution: "natural-compare-lite@npm:1.4.0"
|
|
||||||
checksum: f6cef26f5044515754802c0fc475d81426f3b90fe88c20fabe08771ce1f736ce46e0397c10acb569a4dd0acb84c7f1ee70676122f95d5bfdd747af3a6c6bbaa8
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"natural-compare@npm:^1.4.0":
|
"natural-compare@npm:^1.4.0":
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
resolution: "natural-compare@npm:1.4.0"
|
resolution: "natural-compare@npm:1.4.0"
|
||||||
@@ -45272,8 +45290,8 @@ __metadata:
|
|||||||
"@babel/runtime": ^7.11.2
|
"@babel/runtime": ^7.11.2
|
||||||
"@changesets/changelog-github": ^0.4.8
|
"@changesets/changelog-github": ^0.4.8
|
||||||
"@changesets/cli": ^2.26.0
|
"@changesets/cli": ^2.26.0
|
||||||
"@typescript-eslint/eslint-plugin": ^5.53.0
|
"@typescript-eslint/eslint-plugin": ^6.19.0
|
||||||
"@typescript-eslint/parser": ^5.53.0
|
"@typescript-eslint/parser": ^6.19.0
|
||||||
axios: ^0.21.4
|
axios: ^0.21.4
|
||||||
axios-mock-adapter: ^1.19.0
|
axios-mock-adapter: ^1.19.0
|
||||||
babel-jest: ^26.6.3
|
babel-jest: ^26.6.3
|
||||||
@@ -48723,6 +48741,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ts-api-utils@npm:^1.0.1":
|
||||||
|
version: 1.0.3
|
||||||
|
resolution: "ts-api-utils@npm:1.0.3"
|
||||||
|
peerDependencies:
|
||||||
|
typescript: ">=4.2.0"
|
||||||
|
checksum: 9408338819c3aca2a709f0bc54e3f874227901506cacb1163612a6c8a43df224174feb965a5eafdae16f66fc68fd7bfee8d3275d0fa73fbb8699e03ed26520c9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ts-clone-node@npm:^3.0.0":
|
"ts-clone-node@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "ts-clone-node@npm:3.0.0"
|
resolution: "ts-clone-node@npm:3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user