startx 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +20 -0
- package/.prettierignore +24 -0
- package/.prettierrc.js +52 -0
- package/.vscode/settings.json +3 -0
- package/LICENSE +21 -0
- package/apps/core-server/.env.example +24 -0
- package/apps/core-server/Dockerfile +61 -0
- package/apps/core-server/eslint.config.mjs +47 -0
- package/apps/core-server/package.json +73 -0
- package/apps/core-server/src/config/custom-type.ts +54 -0
- package/apps/core-server/src/events/index.ts +37 -0
- package/apps/core-server/src/index.ts +19 -0
- package/apps/core-server/src/middlewares/auth-middleware.ts +50 -0
- package/apps/core-server/src/middlewares/cors-middleware.ts +6 -0
- package/apps/core-server/src/middlewares/error-middleware.ts +23 -0
- package/apps/core-server/src/middlewares/logger-middleware.ts +21 -0
- package/apps/core-server/src/middlewares/notfound-middleware.ts +14 -0
- package/apps/core-server/src/middlewares/serve-static.ts +24 -0
- package/apps/core-server/src/routes/files/router.ts +7 -0
- package/apps/core-server/src/routes/server.ts +36 -0
- package/apps/core-server/tsconfig.json +10 -0
- package/apps/core-server/tsdown.config.ts +14 -0
- package/biome.json +62 -0
- package/configs/eslint-config/package.json +60 -0
- package/configs/eslint-config/plugins.d.ts +1 -0
- package/configs/eslint-config/src/configs/base.ts +237 -0
- package/configs/eslint-config/src/configs/frontend.ts +62 -0
- package/configs/eslint-config/src/configs/node.ts +10 -0
- package/configs/eslint-config/src/plugin.ts +25 -0
- package/configs/eslint-config/src/rules/index.ts +30 -0
- package/configs/eslint-config/src/rules/no-argument-spread.test.ts +47 -0
- package/configs/eslint-config/src/rules/no-argument-spread.ts +96 -0
- package/configs/eslint-config/src/rules/no-dynamic-import-template.ts +32 -0
- package/configs/eslint-config/src/rules/no-internal-package-import.ts +40 -0
- package/configs/eslint-config/src/rules/no-interpolation-in-regular-string.ts +32 -0
- package/configs/eslint-config/src/rules/no-json-parse-json-stringify.test.ts +34 -0
- package/configs/eslint-config/src/rules/no-json-parse-json-stringify.ts +49 -0
- package/configs/eslint-config/src/rules/no-plain-errors.ts +50 -0
- package/configs/eslint-config/src/rules/no-skipped-tests.ts +61 -0
- package/configs/eslint-config/src/rules/no-top-level-relative-imports-in-backend-module.ts +27 -0
- package/configs/eslint-config/src/rules/no-type-unsafe-event-emitter.ts +33 -0
- package/configs/eslint-config/src/rules/no-uncaught-json-parse.test.ts +21 -0
- package/configs/eslint-config/src/rules/no-uncaught-json-parse.ts +45 -0
- package/configs/eslint-config/src/rules/no-untyped-config-class-field.ts +26 -0
- package/configs/eslint-config/src/rules/no-unused-param-catch-clause.ts +33 -0
- package/configs/eslint-config/src/rules/no-useless-catch-throw.test.ts +34 -0
- package/configs/eslint-config/src/rules/no-useless-catch-throw.ts +47 -0
- package/configs/eslint-config/src/utils/json.ts +21 -0
- package/configs/eslint-config/tsconfig.json +8 -0
- package/configs/eslint-config/tsdown.config.ts +11 -0
- package/configs/eslint-config/vitest.config.ts +3 -0
- package/configs/tsdown-config/package.json +14 -0
- package/configs/tsdown-config/src/config/tsdown.base.ts +13 -0
- package/configs/typescript-config/package.json +10 -0
- package/configs/typescript-config/tsconfig.common.json +32 -0
- package/configs/typescript-config/tsconfig.frontend.json +14 -0
- package/configs/typescript-config/tsconfig.node.json +9 -0
- package/configs/vitest-config/package.json +25 -0
- package/configs/vitest-config/src/base.ts +34 -0
- package/configs/vitest-config/src/frontend.ts +15 -0
- package/configs/vitest-config/src/node.ts +5 -0
- package/configs/vitest-config/tsconfig.json +7 -0
- package/package.json +47 -0
- package/packages/@repo/constants/eslint.config.mjs +21 -0
- package/packages/@repo/constants/package.json +19 -0
- package/packages/@repo/constants/src/api.ts +1 -0
- package/packages/@repo/constants/src/index.ts +8 -0
- package/packages/@repo/constants/src/time.ts +23 -0
- package/packages/@repo/constants/tsconfig.json +7 -0
- package/packages/@repo/db/eslint.config.mjs +21 -0
- package/packages/@repo/db/package.json +30 -0
- package/packages/@repo/db/src/functions.ts +122 -0
- package/packages/@repo/db/src/index.ts +20 -0
- package/packages/@repo/db/src/schema/common.ts +49 -0
- package/packages/@repo/db/src/schema/index.ts +1 -0
- package/packages/@repo/db/tsconfig.json +13 -0
- package/packages/@repo/lib/eslint.config.mjs +49 -0
- package/packages/@repo/lib/package.json +57 -0
- package/packages/@repo/lib/src/bucket-module/file-storage.ts +49 -0
- package/packages/@repo/lib/src/bucket-module/s3-storage.ts +114 -0
- package/packages/@repo/lib/src/bucket-module/utils.ts +11 -0
- package/packages/@repo/lib/src/command-module.ts +77 -0
- package/packages/@repo/lib/src/constants.ts +3 -0
- package/packages/@repo/lib/src/cookie-module.ts +42 -0
- package/packages/@repo/lib/src/custom-type.ts +54 -0
- package/packages/@repo/lib/src/env.ts +13 -0
- package/packages/@repo/lib/src/error-handlers-module/index.ts +11 -0
- package/packages/@repo/lib/src/file-system/index.ts +90 -0
- package/packages/@repo/lib/src/hashing-module.ts +9 -0
- package/packages/@repo/lib/src/index.ts +27 -0
- package/packages/@repo/lib/src/logger-module/log-config.ts +16 -0
- package/packages/@repo/lib/src/logger-module/logger.ts +78 -0
- package/packages/@repo/lib/src/logger-module/memory-profiler.ts +65 -0
- package/packages/@repo/lib/src/mail-module/api.ts +0 -0
- package/packages/@repo/lib/src/mail-module/mock.ts +8 -0
- package/packages/@repo/lib/src/mail-module/nodemailer.ts +45 -0
- package/packages/@repo/lib/src/notification-module/index.ts +172 -0
- package/packages/@repo/lib/src/notification-module/push-notification.ts +90 -0
- package/packages/@repo/lib/src/oauth2-client.ts +109 -0
- package/packages/@repo/lib/src/otp-module.ts +98 -0
- package/packages/@repo/lib/src/pagination-module.ts +49 -0
- package/packages/@repo/lib/src/token-module.ts +35 -0
- package/packages/@repo/lib/src/user-session.ts +117 -0
- package/packages/@repo/lib/src/utils.ts +42 -0
- package/packages/@repo/lib/src/validation-module.ts +187 -0
- package/packages/@repo/lib/tsconfig.json +7 -0
- package/packages/@repo/mail/package.json +29 -0
- package/packages/@repo/mail/src/emails/admin/OtpEmail.tsx +168 -0
- package/packages/@repo/mail/src/index.ts +13 -0
- package/packages/@repo/mail/tsconfig.build.json +14 -0
- package/packages/@repo/mail/tsconfig.json +13 -0
- package/packages/@repo/mail/tsdown.config.ts +9 -0
- package/packages/@repo/redis/eslint.config.mjs +8 -0
- package/packages/@repo/redis/package.json +31 -0
- package/packages/@repo/redis/src/index.ts +2 -0
- package/packages/@repo/redis/src/lib/redis-client.ts +23 -0
- package/packages/@repo/redis/src/lib/redis-module.ts +3 -0
- package/packages/@repo/redis/tsconfig.json +12 -0
- package/packages/ui/components.json +17 -0
- package/packages/ui/eslint.config.mjs +18 -0
- package/packages/ui/package.json +67 -0
- package/packages/ui/postcss.config.mjs +9 -0
- package/packages/ui/src/components/custom/form-wrapper.tsx +551 -0
- package/packages/ui/src/components/custom/grid-component.tsx +23 -0
- package/packages/ui/src/components/custom/hover-tool.tsx +38 -0
- package/packages/ui/src/components/custom/image-picker.tsx +109 -0
- package/packages/ui/src/components/custom/no-content.tsx +37 -0
- package/packages/ui/src/components/custom/page-container.tsx +24 -0
- package/packages/ui/src/components/custom/page-section.tsx +59 -0
- package/packages/ui/src/components/custom/simple-popover.tsx +29 -0
- package/packages/ui/src/components/custom/switch-component.tsx +20 -0
- package/packages/ui/src/components/custom/theme-provider.tsx +74 -0
- package/packages/ui/src/components/custom/typography.tsx +111 -0
- package/packages/ui/src/components/extensions/carousel.tsx +392 -0
- package/packages/ui/src/components/hooks/event/use-click.tsx +39 -0
- package/packages/ui/src/components/hooks/time/useDebounce.tsx +21 -0
- package/packages/ui/src/components/hooks/time/useInterval.tsx +35 -0
- package/packages/ui/src/components/hooks/time/useTimeout.tsx +19 -0
- package/packages/ui/src/components/hooks/time/useTimer.tsx +51 -0
- package/packages/ui/src/components/hooks/use-media-query.tsx +19 -0
- package/packages/ui/src/components/hooks/use-persistent-storage.tsx +52 -0
- package/packages/ui/src/components/hooks/use-update-effect.tsx +13 -0
- package/packages/ui/src/components/hooks/use-window-dimension.tsx +30 -0
- package/packages/ui/src/components/lib/utils.ts +242 -0
- package/packages/ui/src/components/lucide.tsx +3 -0
- package/packages/ui/src/components/sonner.tsx +1 -0
- package/packages/ui/src/components/ui/alert-dialog.tsx +116 -0
- package/packages/ui/src/components/ui/avatar.tsx +53 -0
- package/packages/ui/src/components/ui/badge.tsx +46 -0
- package/packages/ui/src/components/ui/breadcrumb.tsx +109 -0
- package/packages/ui/src/components/ui/button.tsx +96 -0
- package/packages/ui/src/components/ui/card.tsx +92 -0
- package/packages/ui/src/components/ui/carousel.tsx +243 -0
- package/packages/ui/src/components/ui/checkbox.tsx +32 -0
- package/packages/ui/src/components/ui/command.tsx +155 -0
- package/packages/ui/src/components/ui/dialog.tsx +127 -0
- package/packages/ui/src/components/ui/dropdown-menu.tsx +226 -0
- package/packages/ui/src/components/ui/form.tsx +165 -0
- package/packages/ui/src/components/ui/input-otp.tsx +76 -0
- package/packages/ui/src/components/ui/input.tsx +21 -0
- package/packages/ui/src/components/ui/label.tsx +24 -0
- package/packages/ui/src/components/ui/multiple-select.tsx +510 -0
- package/packages/ui/src/components/ui/popover.tsx +42 -0
- package/packages/ui/src/components/ui/select.tsx +170 -0
- package/packages/ui/src/components/ui/separator.tsx +28 -0
- package/packages/ui/src/components/ui/sheet.tsx +130 -0
- package/packages/ui/src/components/ui/skeleton.tsx +13 -0
- package/packages/ui/src/components/ui/spinner.tsx +16 -0
- package/packages/ui/src/components/ui/switch.tsx +28 -0
- package/packages/ui/src/components/ui/table.tsx +116 -0
- package/packages/ui/src/components/ui/tabs.tsx +54 -0
- package/packages/ui/src/components/ui/textarea.tsx +18 -0
- package/packages/ui/src/components/ui/timeline.tsx +118 -0
- package/packages/ui/src/components/ui/tooltip.tsx +30 -0
- package/packages/ui/src/components/util/n-formattor.ts +22 -0
- package/packages/ui/src/components/util/storage.ts +37 -0
- package/packages/ui/src/globals.css +87 -0
- package/packages/ui/tailwind.config.ts +94 -0
- package/packages/ui/tsconfig.json +12 -0
- package/pnpm-workspace.yaml +43 -0
- package/turbo.json +77 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoInternalPackageImportRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: "no-internal-package-import",
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow imports from internal package paths (e.g. `/pkg/src/...`).',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noInternalPackageImport:
|
|
12
|
+
'Import from "{{ packageRoot }}", not from the internal `/src/` path.',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
schema: [],
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
const INTERNAL_IMPORT_REGEX = /^(?<packageRoot>\/[^/]+)\/src\//;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
ImportDeclaration(node) {
|
|
23
|
+
if (typeof node.source.type !== 'string') return;
|
|
24
|
+
|
|
25
|
+
const match = node.source.value.match(INTERNAL_IMPORT_REGEX);
|
|
26
|
+
|
|
27
|
+
if (!match?.groups) return;
|
|
28
|
+
|
|
29
|
+
const { packageRoot } = match.groups;
|
|
30
|
+
|
|
31
|
+
context.report({
|
|
32
|
+
node: node.source,
|
|
33
|
+
messageId: 'noInternalPackageImport',
|
|
34
|
+
fix: (fixer) => fixer.replaceText(node.source, `"${packageRoot}"`),
|
|
35
|
+
data: { packageRoot },
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoInterpolationInRegularStringRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: 'no-interpolation-in-regular-string',
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'String interpolation `${...}` requires backticks, not single or double quotes.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
useBackticks: 'Use backticks to interpolate',
|
|
12
|
+
},
|
|
13
|
+
fixable: 'code',
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
Literal(node) {
|
|
20
|
+
if (typeof node.value !== 'string') return;
|
|
21
|
+
|
|
22
|
+
if (/\$\{/.test(node.value)) {
|
|
23
|
+
context.report({
|
|
24
|
+
messageId: 'useBackticks',
|
|
25
|
+
node,
|
|
26
|
+
fix: (fixer) => fixer.replaceText(node, `\`${node.value}\``),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RuleTester } from '@typescript-eslint/rule-tester';
|
|
2
|
+
import { NoJsonParseJsonStringifyRule } from './no-json-parse-json-stringify.js';
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run('no-json-parse-json-stringify', NoJsonParseJsonStringifyRule, {
|
|
7
|
+
valid: [
|
|
8
|
+
{
|
|
9
|
+
code: 'deepCopy(foo)',
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
invalid: [
|
|
13
|
+
{
|
|
14
|
+
code: 'JSON.parse(JSON.stringify(foo))',
|
|
15
|
+
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
|
16
|
+
output: 'deepCopy(foo)',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
code: 'JSON.parse(JSON.stringify(foo.bar))',
|
|
20
|
+
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
|
21
|
+
output: 'deepCopy(foo.bar)',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
code: 'JSON.parse(JSON.stringify(foo.bar.baz))',
|
|
25
|
+
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
|
26
|
+
output: 'deepCopy(foo.bar.baz)',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
code: 'JSON.parse(JSON.stringify(foo.bar[baz]))',
|
|
30
|
+
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
|
31
|
+
output: 'deepCopy(foo.bar[baz])',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isJsonParseCall, isJsonStringifyCall } from '../utils/json.js';
|
|
2
|
+
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
3
|
+
|
|
4
|
+
export const NoJsonParseJsonStringifyRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
5
|
+
name: 'no-json-parse-json-stringify',
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description:
|
|
10
|
+
'Calls to `JSON.parse(JSON.stringify(arg))` must be replaced with `deepCopy(arg)` from `workflow`.',
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
noJsonParseJsonStringify: 'Replace with `deepCopy({{ argText }})`',
|
|
15
|
+
},
|
|
16
|
+
fixable: 'code',
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
CallExpression(node) {
|
|
22
|
+
if (isJsonParseCall(node) && isJsonStringifyCall(node)) {
|
|
23
|
+
const [callExpression] = node.arguments;
|
|
24
|
+
|
|
25
|
+
if (callExpression.type !== TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { arguments: args } = callExpression;
|
|
30
|
+
|
|
31
|
+
if (!Array.isArray(args) || args.length !== 1) return;
|
|
32
|
+
|
|
33
|
+
const [arg] = args;
|
|
34
|
+
|
|
35
|
+
if (!arg) return;
|
|
36
|
+
|
|
37
|
+
const argText = context.sourceCode.getText(arg);
|
|
38
|
+
|
|
39
|
+
context.report({
|
|
40
|
+
messageId: 'noJsonParseJsonStringify',
|
|
41
|
+
node,
|
|
42
|
+
data: { argText },
|
|
43
|
+
fix: (fixer) => fixer.replaceText(node, `deepCopy(${argText})`),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoPlainErrorsRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: 'no-plain-errors',
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description:
|
|
9
|
+
'Only `ApplicationError` (from the `workflow` package) or its child classes must be thrown. This ensures the error will be normalized when reported to Sentry, if applicable.',
|
|
10
|
+
},
|
|
11
|
+
messages: {
|
|
12
|
+
useApplicationError:
|
|
13
|
+
'Throw an `ApplicationError` (from the `workflow` package) or its child classes.',
|
|
14
|
+
},
|
|
15
|
+
fixable: 'code',
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
ThrowStatement(node) {
|
|
22
|
+
if (!node.argument) return;
|
|
23
|
+
|
|
24
|
+
const isNewError =
|
|
25
|
+
node.argument.type === TSESTree.AST_NODE_TYPES.NewExpression &&
|
|
26
|
+
node.argument.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
27
|
+
node.argument.callee.name === 'Error';
|
|
28
|
+
|
|
29
|
+
const isNewlessError =
|
|
30
|
+
node.argument.type === TSESTree.AST_NODE_TYPES.CallExpression &&
|
|
31
|
+
node.argument.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
32
|
+
node.argument.callee.name === 'Error';
|
|
33
|
+
|
|
34
|
+
if (isNewError || isNewlessError) {
|
|
35
|
+
return context.report({
|
|
36
|
+
messageId: 'useApplicationError',
|
|
37
|
+
node,
|
|
38
|
+
fix: (fixer) =>
|
|
39
|
+
fixer.replaceText(
|
|
40
|
+
node,
|
|
41
|
+
`throw new ApplicationError(${(node.argument as TSESTree.CallExpression).arguments
|
|
42
|
+
.map((arg) => context.sourceCode.getText(arg))
|
|
43
|
+
.join(', ')})`,
|
|
44
|
+
),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
+
|
|
3
|
+
export const NoSkippedTestsRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: "no-skipped-tests",
|
|
5
|
+
meta: {
|
|
6
|
+
type: "problem",
|
|
7
|
+
docs: {
|
|
8
|
+
description: "Tests must not be skipped.",
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
removeSkip: "Remove `.skip()` call",
|
|
12
|
+
removeOnly: "Remove `.only()` call",
|
|
13
|
+
removeXPrefix: "Remove `x` prefix",
|
|
14
|
+
},
|
|
15
|
+
fixable: "code",
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
const TESTING_FUNCTIONS = new Set(["test", "it", "describe"]);
|
|
21
|
+
const SKIPPING_METHODS = new Set(["skip", "only"]);
|
|
22
|
+
const PREFIXED_TESTING_FUNCTIONS = new Set(["xtest", "xit", "xdescribe"]);
|
|
23
|
+
const toMessageId = (s: string) =>
|
|
24
|
+
`remove${s.charAt(0).toUpperCase()}${s.slice(1)}` as
|
|
25
|
+
| "removeSkip"
|
|
26
|
+
| "removeOnly"
|
|
27
|
+
| "removeXPrefix";
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
MemberExpression(node) {
|
|
31
|
+
if (
|
|
32
|
+
node.object.type === "Identifier" &&
|
|
33
|
+
TESTING_FUNCTIONS.has(node.object.name) &&
|
|
34
|
+
node.property.type === "Identifier" &&
|
|
35
|
+
SKIPPING_METHODS.has(node.property.name)
|
|
36
|
+
) {
|
|
37
|
+
context.report({
|
|
38
|
+
messageId: toMessageId(node.property.name),
|
|
39
|
+
node,
|
|
40
|
+
fix: (fixer) => {
|
|
41
|
+
const [start, end] = node.property.range;
|
|
42
|
+
return fixer.removeRange([start - ".".length, end]);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
CallExpression(node) {
|
|
48
|
+
if (
|
|
49
|
+
node.callee.type === "Identifier" &&
|
|
50
|
+
PREFIXED_TESTING_FUNCTIONS.has(node.callee.name)
|
|
51
|
+
) {
|
|
52
|
+
context.report({
|
|
53
|
+
messageId: "removeXPrefix",
|
|
54
|
+
node,
|
|
55
|
+
fix: (fixer) => fixer.replaceText(node.callee, "test"),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoTopLevelRelativeImportsInBackendModuleRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: 'no-top-level-relative-imports-in-backend-module',
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description:
|
|
9
|
+
'Relative imports in `.module.ts` files must be placed inside the `init` method. This ensures that module imports are loaded only when the module is used.',
|
|
10
|
+
},
|
|
11
|
+
messages: {
|
|
12
|
+
placeInsideInit:
|
|
13
|
+
"Place this relative import inside the `init` method, using `await import('./path')` syntax.",
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
return {
|
|
20
|
+
'Program > ImportDeclaration'(node: TSESTree.ImportDeclaration) {
|
|
21
|
+
if (node.source.value.startsWith('.')) {
|
|
22
|
+
context.report({ node, messageId: 'placeInsideInit' });
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoTypeUnsafeEventEmitterRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: 'no-type-unsafe-event-emitter',
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow extending from `EventEmitter`, which is not type-safe.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noExtendsEventEmitter: 'Extend from the type-safe `TypedEmitter` class instead.',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
defaultOptions: [],
|
|
16
|
+
create(context) {
|
|
17
|
+
return {
|
|
18
|
+
ClassDeclaration(node) {
|
|
19
|
+
if (
|
|
20
|
+
node.superClass &&
|
|
21
|
+
node.superClass.type === 'Identifier' &&
|
|
22
|
+
node.superClass.name === 'EventEmitter' &&
|
|
23
|
+
node.id?.name !== 'TypedEmitter'
|
|
24
|
+
) {
|
|
25
|
+
context.report({
|
|
26
|
+
node: node.superClass,
|
|
27
|
+
messageId: 'noExtendsEventEmitter',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RuleTester } from "@typescript-eslint/rule-tester";
|
|
2
|
+
import { NoUncaughtJsonParseRule } from "./no-uncaught-json-parse.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("no-uncaught-json-parse", NoUncaughtJsonParseRule, {
|
|
7
|
+
valid: [
|
|
8
|
+
{
|
|
9
|
+
code: "try { JSON.parse(foo) } catch (e) {}",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
code: "JSON.parse(JSON.stringify(foo))",
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
invalid: [
|
|
16
|
+
{
|
|
17
|
+
code: "JSON.parse(foo)",
|
|
18
|
+
errors: [{ messageId: "noUncaughtJsonParse" }],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { isJsonParseCall, isJsonStringifyCall } from '../utils/json.js';
|
|
3
|
+
|
|
4
|
+
export const NoUncaughtJsonParseRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
5
|
+
name: 'no-uncaught-json-parse',
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
hasSuggestions: true,
|
|
9
|
+
docs: {
|
|
10
|
+
description:
|
|
11
|
+
'Calls to `JSON.parse()` must be replaced with `jsonParse()` from `workflow` or surrounded with a try/catch block.',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
noUncaughtJsonParse:
|
|
16
|
+
'Use `jsonParse()` from `workflow` or surround the `JSON.parse()` call with a try/catch block.',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create({ report, sourceCode }) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (!isJsonParseCall(node)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isJsonStringifyCall(node)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
sourceCode.getAncestors(node).find((node) => node.type === 'TryStatement') !== undefined
|
|
33
|
+
) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Found a JSON.parse() call not wrapped into a try/catch, so report it
|
|
38
|
+
report({
|
|
39
|
+
messageId: 'noUncaughtJsonParse',
|
|
40
|
+
node,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoUntypedConfigClassFieldRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: "no-untyped-config-class-field",
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Enforce explicit typing of config class fields',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noUntypedConfigClassField:
|
|
12
|
+
'Class field must have an explicit type annotation, e.g. `field: type = value`.',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
PropertyDefinition(node) {
|
|
20
|
+
if (!node.typeAnnotation) {
|
|
21
|
+
context.report({ node: node.key, messageId: 'noUntypedConfigClassField' });
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoUnusedParamInCatchClauseRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: "no-unused-param-catch-clause",
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Unused param in catch clause must be omitted.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
removeUnusedParam: 'Remove unused param in catch clause',
|
|
12
|
+
},
|
|
13
|
+
fixable: 'code',
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
CatchClause(node) {
|
|
20
|
+
if (node.param?.type === 'Identifier' && node.param.name.startsWith('_')) {
|
|
21
|
+
const start = node.range[0] + 'catch '.length;
|
|
22
|
+
const end = node.param.range[1] + '()'.length;
|
|
23
|
+
|
|
24
|
+
context.report({
|
|
25
|
+
messageId: 'removeUnusedParam',
|
|
26
|
+
node,
|
|
27
|
+
fix: (fixer) => fixer.removeRange([start, end]),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RuleTester } from "@typescript-eslint/rule-tester";
|
|
2
|
+
import { NoUselessCatchThrowRule } from "./no-useless-catch-throw.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("no-useless-catch-throw", NoUselessCatchThrowRule, {
|
|
7
|
+
valid: [
|
|
8
|
+
{
|
|
9
|
+
code: "try { foo(); } catch (e) { console.error(e); }",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
code: 'try { foo(); } catch (e) { throw new Error("Custom error"); }',
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
invalid: [
|
|
16
|
+
{
|
|
17
|
+
code: `
|
|
18
|
+
try {
|
|
19
|
+
// Some comment
|
|
20
|
+
if (foo) {
|
|
21
|
+
bar();
|
|
22
|
+
}
|
|
23
|
+
} catch (e) {
|
|
24
|
+
throw e;
|
|
25
|
+
}`,
|
|
26
|
+
errors: [{ messageId: "noUselessCatchThrow" }],
|
|
27
|
+
output: `
|
|
28
|
+
// Some comment
|
|
29
|
+
if (foo) {
|
|
30
|
+
bar();
|
|
31
|
+
}`,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const NoUselessCatchThrowRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
4
|
+
name: 'no-useless-catch-throw',
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow `try-catch` blocks where the `catch` only contains a `throw error`.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noUselessCatchThrow: 'Remove useless `catch` block.',
|
|
12
|
+
},
|
|
13
|
+
fixable: 'code',
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
CatchClause(node) {
|
|
20
|
+
if (
|
|
21
|
+
node.body.body.length === 1 &&
|
|
22
|
+
node.body.body[0].type === 'ThrowStatement' &&
|
|
23
|
+
node.body.body[0].argument.type === 'Identifier' &&
|
|
24
|
+
node.param?.type === 'Identifier' &&
|
|
25
|
+
node.body.body[0].argument.name === node.param.name
|
|
26
|
+
) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId: 'noUselessCatchThrow',
|
|
30
|
+
fix(fixer) {
|
|
31
|
+
const tryStatement = node.parent;
|
|
32
|
+
const tryBlock = tryStatement.block;
|
|
33
|
+
const sourceCode = context.sourceCode;
|
|
34
|
+
const tryBlockText = sourceCode.getText(tryBlock);
|
|
35
|
+
const tryBlockTextWithoutBraces = tryBlockText.slice(1, -1).trim();
|
|
36
|
+
const indentedTryBlockText = tryBlockTextWithoutBraces
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map((line) => line.replace(/\t/, ''))
|
|
39
|
+
.join('\n');
|
|
40
|
+
return fixer.replaceText(tryStatement, indentedTryBlockText);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
export const isJsonParseCall = (node: TSESTree.CallExpression) =>
|
|
4
|
+
node.callee.type === 'MemberExpression' &&
|
|
5
|
+
node.callee.object.type === 'Identifier' &&
|
|
6
|
+
node.callee.object.name === 'JSON' &&
|
|
7
|
+
node.callee.property.type === 'Identifier' &&
|
|
8
|
+
node.callee.property.name === 'parse';
|
|
9
|
+
|
|
10
|
+
export const isJsonStringifyCall = (node: TSESTree.CallExpression) => {
|
|
11
|
+
const parseArg = node.arguments?.[0];
|
|
12
|
+
return (
|
|
13
|
+
parseArg !== undefined &&
|
|
14
|
+
parseArg.type === 'CallExpression' &&
|
|
15
|
+
parseArg.callee.type === 'MemberExpression' &&
|
|
16
|
+
parseArg.callee.object.type === 'Identifier' &&
|
|
17
|
+
parseArg.callee.object.name === 'JSON' &&
|
|
18
|
+
parseArg.callee.property.type === 'Identifier' &&
|
|
19
|
+
parseArg.callee.property.name === 'stringify'
|
|
20
|
+
);
|
|
21
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tsdown-config",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"exports": "./src/config/tsdown.base.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"clean": "rimraf dist",
|
|
12
|
+
"deep:clean": "rimraf node_modules dist"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from "tsdown";
|
|
2
|
+
export const baseConfig = defineConfig({
|
|
3
|
+
entry: ["./src/index.ts"],
|
|
4
|
+
format: ["esm"],
|
|
5
|
+
clean: true,
|
|
6
|
+
target: "es2022",
|
|
7
|
+
sourcemap: false,
|
|
8
|
+
minify: true,
|
|
9
|
+
treeshake: true,
|
|
10
|
+
shims: true,
|
|
11
|
+
unbundle: false,
|
|
12
|
+
external: [/^@unrs\//],
|
|
13
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
|
|
15
|
+
"experimentalDecorators": true,
|
|
16
|
+
"emitDecoratorMetadata": true,
|
|
17
|
+
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"useUnknownInCatchVariables": true,
|
|
22
|
+
"strictNullChecks": true,
|
|
23
|
+
"noImplicitAny": true,
|
|
24
|
+
"noImplicitReturns": true,
|
|
25
|
+
"noFallthroughCasesInSwitch": true,
|
|
26
|
+
"forceConsistentCasingInFileNames": true,
|
|
27
|
+
"removeComments": true,
|
|
28
|
+
|
|
29
|
+
"tsBuildInfoFile": "dist/typecheck.tsbuildinfo"
|
|
30
|
+
},
|
|
31
|
+
"exclude": ["node_modules", "dist"]
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.common.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "esnext",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"importHelpers": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"incremental": false,
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
|
|
13
|
+
}
|
|
14
|
+
}
|