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.
Files changed (181) hide show
  1. package/.editorconfig +20 -0
  2. package/.prettierignore +24 -0
  3. package/.prettierrc.js +52 -0
  4. package/.vscode/settings.json +3 -0
  5. package/LICENSE +21 -0
  6. package/apps/core-server/.env.example +24 -0
  7. package/apps/core-server/Dockerfile +61 -0
  8. package/apps/core-server/eslint.config.mjs +47 -0
  9. package/apps/core-server/package.json +73 -0
  10. package/apps/core-server/src/config/custom-type.ts +54 -0
  11. package/apps/core-server/src/events/index.ts +37 -0
  12. package/apps/core-server/src/index.ts +19 -0
  13. package/apps/core-server/src/middlewares/auth-middleware.ts +50 -0
  14. package/apps/core-server/src/middlewares/cors-middleware.ts +6 -0
  15. package/apps/core-server/src/middlewares/error-middleware.ts +23 -0
  16. package/apps/core-server/src/middlewares/logger-middleware.ts +21 -0
  17. package/apps/core-server/src/middlewares/notfound-middleware.ts +14 -0
  18. package/apps/core-server/src/middlewares/serve-static.ts +24 -0
  19. package/apps/core-server/src/routes/files/router.ts +7 -0
  20. package/apps/core-server/src/routes/server.ts +36 -0
  21. package/apps/core-server/tsconfig.json +10 -0
  22. package/apps/core-server/tsdown.config.ts +14 -0
  23. package/biome.json +62 -0
  24. package/configs/eslint-config/package.json +60 -0
  25. package/configs/eslint-config/plugins.d.ts +1 -0
  26. package/configs/eslint-config/src/configs/base.ts +237 -0
  27. package/configs/eslint-config/src/configs/frontend.ts +62 -0
  28. package/configs/eslint-config/src/configs/node.ts +10 -0
  29. package/configs/eslint-config/src/plugin.ts +25 -0
  30. package/configs/eslint-config/src/rules/index.ts +30 -0
  31. package/configs/eslint-config/src/rules/no-argument-spread.test.ts +47 -0
  32. package/configs/eslint-config/src/rules/no-argument-spread.ts +96 -0
  33. package/configs/eslint-config/src/rules/no-dynamic-import-template.ts +32 -0
  34. package/configs/eslint-config/src/rules/no-internal-package-import.ts +40 -0
  35. package/configs/eslint-config/src/rules/no-interpolation-in-regular-string.ts +32 -0
  36. package/configs/eslint-config/src/rules/no-json-parse-json-stringify.test.ts +34 -0
  37. package/configs/eslint-config/src/rules/no-json-parse-json-stringify.ts +49 -0
  38. package/configs/eslint-config/src/rules/no-plain-errors.ts +50 -0
  39. package/configs/eslint-config/src/rules/no-skipped-tests.ts +61 -0
  40. package/configs/eslint-config/src/rules/no-top-level-relative-imports-in-backend-module.ts +27 -0
  41. package/configs/eslint-config/src/rules/no-type-unsafe-event-emitter.ts +33 -0
  42. package/configs/eslint-config/src/rules/no-uncaught-json-parse.test.ts +21 -0
  43. package/configs/eslint-config/src/rules/no-uncaught-json-parse.ts +45 -0
  44. package/configs/eslint-config/src/rules/no-untyped-config-class-field.ts +26 -0
  45. package/configs/eslint-config/src/rules/no-unused-param-catch-clause.ts +33 -0
  46. package/configs/eslint-config/src/rules/no-useless-catch-throw.test.ts +34 -0
  47. package/configs/eslint-config/src/rules/no-useless-catch-throw.ts +47 -0
  48. package/configs/eslint-config/src/utils/json.ts +21 -0
  49. package/configs/eslint-config/tsconfig.json +8 -0
  50. package/configs/eslint-config/tsdown.config.ts +11 -0
  51. package/configs/eslint-config/vitest.config.ts +3 -0
  52. package/configs/tsdown-config/package.json +14 -0
  53. package/configs/tsdown-config/src/config/tsdown.base.ts +13 -0
  54. package/configs/typescript-config/package.json +10 -0
  55. package/configs/typescript-config/tsconfig.common.json +32 -0
  56. package/configs/typescript-config/tsconfig.frontend.json +14 -0
  57. package/configs/typescript-config/tsconfig.node.json +9 -0
  58. package/configs/vitest-config/package.json +25 -0
  59. package/configs/vitest-config/src/base.ts +34 -0
  60. package/configs/vitest-config/src/frontend.ts +15 -0
  61. package/configs/vitest-config/src/node.ts +5 -0
  62. package/configs/vitest-config/tsconfig.json +7 -0
  63. package/package.json +47 -0
  64. package/packages/@repo/constants/eslint.config.mjs +21 -0
  65. package/packages/@repo/constants/package.json +19 -0
  66. package/packages/@repo/constants/src/api.ts +1 -0
  67. package/packages/@repo/constants/src/index.ts +8 -0
  68. package/packages/@repo/constants/src/time.ts +23 -0
  69. package/packages/@repo/constants/tsconfig.json +7 -0
  70. package/packages/@repo/db/eslint.config.mjs +21 -0
  71. package/packages/@repo/db/package.json +30 -0
  72. package/packages/@repo/db/src/functions.ts +122 -0
  73. package/packages/@repo/db/src/index.ts +20 -0
  74. package/packages/@repo/db/src/schema/common.ts +49 -0
  75. package/packages/@repo/db/src/schema/index.ts +1 -0
  76. package/packages/@repo/db/tsconfig.json +13 -0
  77. package/packages/@repo/lib/eslint.config.mjs +49 -0
  78. package/packages/@repo/lib/package.json +57 -0
  79. package/packages/@repo/lib/src/bucket-module/file-storage.ts +49 -0
  80. package/packages/@repo/lib/src/bucket-module/s3-storage.ts +114 -0
  81. package/packages/@repo/lib/src/bucket-module/utils.ts +11 -0
  82. package/packages/@repo/lib/src/command-module.ts +77 -0
  83. package/packages/@repo/lib/src/constants.ts +3 -0
  84. package/packages/@repo/lib/src/cookie-module.ts +42 -0
  85. package/packages/@repo/lib/src/custom-type.ts +54 -0
  86. package/packages/@repo/lib/src/env.ts +13 -0
  87. package/packages/@repo/lib/src/error-handlers-module/index.ts +11 -0
  88. package/packages/@repo/lib/src/file-system/index.ts +90 -0
  89. package/packages/@repo/lib/src/hashing-module.ts +9 -0
  90. package/packages/@repo/lib/src/index.ts +27 -0
  91. package/packages/@repo/lib/src/logger-module/log-config.ts +16 -0
  92. package/packages/@repo/lib/src/logger-module/logger.ts +78 -0
  93. package/packages/@repo/lib/src/logger-module/memory-profiler.ts +65 -0
  94. package/packages/@repo/lib/src/mail-module/api.ts +0 -0
  95. package/packages/@repo/lib/src/mail-module/mock.ts +8 -0
  96. package/packages/@repo/lib/src/mail-module/nodemailer.ts +45 -0
  97. package/packages/@repo/lib/src/notification-module/index.ts +172 -0
  98. package/packages/@repo/lib/src/notification-module/push-notification.ts +90 -0
  99. package/packages/@repo/lib/src/oauth2-client.ts +109 -0
  100. package/packages/@repo/lib/src/otp-module.ts +98 -0
  101. package/packages/@repo/lib/src/pagination-module.ts +49 -0
  102. package/packages/@repo/lib/src/token-module.ts +35 -0
  103. package/packages/@repo/lib/src/user-session.ts +117 -0
  104. package/packages/@repo/lib/src/utils.ts +42 -0
  105. package/packages/@repo/lib/src/validation-module.ts +187 -0
  106. package/packages/@repo/lib/tsconfig.json +7 -0
  107. package/packages/@repo/mail/package.json +29 -0
  108. package/packages/@repo/mail/src/emails/admin/OtpEmail.tsx +168 -0
  109. package/packages/@repo/mail/src/index.ts +13 -0
  110. package/packages/@repo/mail/tsconfig.build.json +14 -0
  111. package/packages/@repo/mail/tsconfig.json +13 -0
  112. package/packages/@repo/mail/tsdown.config.ts +9 -0
  113. package/packages/@repo/redis/eslint.config.mjs +8 -0
  114. package/packages/@repo/redis/package.json +31 -0
  115. package/packages/@repo/redis/src/index.ts +2 -0
  116. package/packages/@repo/redis/src/lib/redis-client.ts +23 -0
  117. package/packages/@repo/redis/src/lib/redis-module.ts +3 -0
  118. package/packages/@repo/redis/tsconfig.json +12 -0
  119. package/packages/ui/components.json +17 -0
  120. package/packages/ui/eslint.config.mjs +18 -0
  121. package/packages/ui/package.json +67 -0
  122. package/packages/ui/postcss.config.mjs +9 -0
  123. package/packages/ui/src/components/custom/form-wrapper.tsx +551 -0
  124. package/packages/ui/src/components/custom/grid-component.tsx +23 -0
  125. package/packages/ui/src/components/custom/hover-tool.tsx +38 -0
  126. package/packages/ui/src/components/custom/image-picker.tsx +109 -0
  127. package/packages/ui/src/components/custom/no-content.tsx +37 -0
  128. package/packages/ui/src/components/custom/page-container.tsx +24 -0
  129. package/packages/ui/src/components/custom/page-section.tsx +59 -0
  130. package/packages/ui/src/components/custom/simple-popover.tsx +29 -0
  131. package/packages/ui/src/components/custom/switch-component.tsx +20 -0
  132. package/packages/ui/src/components/custom/theme-provider.tsx +74 -0
  133. package/packages/ui/src/components/custom/typography.tsx +111 -0
  134. package/packages/ui/src/components/extensions/carousel.tsx +392 -0
  135. package/packages/ui/src/components/hooks/event/use-click.tsx +39 -0
  136. package/packages/ui/src/components/hooks/time/useDebounce.tsx +21 -0
  137. package/packages/ui/src/components/hooks/time/useInterval.tsx +35 -0
  138. package/packages/ui/src/components/hooks/time/useTimeout.tsx +19 -0
  139. package/packages/ui/src/components/hooks/time/useTimer.tsx +51 -0
  140. package/packages/ui/src/components/hooks/use-media-query.tsx +19 -0
  141. package/packages/ui/src/components/hooks/use-persistent-storage.tsx +52 -0
  142. package/packages/ui/src/components/hooks/use-update-effect.tsx +13 -0
  143. package/packages/ui/src/components/hooks/use-window-dimension.tsx +30 -0
  144. package/packages/ui/src/components/lib/utils.ts +242 -0
  145. package/packages/ui/src/components/lucide.tsx +3 -0
  146. package/packages/ui/src/components/sonner.tsx +1 -0
  147. package/packages/ui/src/components/ui/alert-dialog.tsx +116 -0
  148. package/packages/ui/src/components/ui/avatar.tsx +53 -0
  149. package/packages/ui/src/components/ui/badge.tsx +46 -0
  150. package/packages/ui/src/components/ui/breadcrumb.tsx +109 -0
  151. package/packages/ui/src/components/ui/button.tsx +96 -0
  152. package/packages/ui/src/components/ui/card.tsx +92 -0
  153. package/packages/ui/src/components/ui/carousel.tsx +243 -0
  154. package/packages/ui/src/components/ui/checkbox.tsx +32 -0
  155. package/packages/ui/src/components/ui/command.tsx +155 -0
  156. package/packages/ui/src/components/ui/dialog.tsx +127 -0
  157. package/packages/ui/src/components/ui/dropdown-menu.tsx +226 -0
  158. package/packages/ui/src/components/ui/form.tsx +165 -0
  159. package/packages/ui/src/components/ui/input-otp.tsx +76 -0
  160. package/packages/ui/src/components/ui/input.tsx +21 -0
  161. package/packages/ui/src/components/ui/label.tsx +24 -0
  162. package/packages/ui/src/components/ui/multiple-select.tsx +510 -0
  163. package/packages/ui/src/components/ui/popover.tsx +42 -0
  164. package/packages/ui/src/components/ui/select.tsx +170 -0
  165. package/packages/ui/src/components/ui/separator.tsx +28 -0
  166. package/packages/ui/src/components/ui/sheet.tsx +130 -0
  167. package/packages/ui/src/components/ui/skeleton.tsx +13 -0
  168. package/packages/ui/src/components/ui/spinner.tsx +16 -0
  169. package/packages/ui/src/components/ui/switch.tsx +28 -0
  170. package/packages/ui/src/components/ui/table.tsx +116 -0
  171. package/packages/ui/src/components/ui/tabs.tsx +54 -0
  172. package/packages/ui/src/components/ui/textarea.tsx +18 -0
  173. package/packages/ui/src/components/ui/timeline.tsx +118 -0
  174. package/packages/ui/src/components/ui/tooltip.tsx +30 -0
  175. package/packages/ui/src/components/util/n-formattor.ts +22 -0
  176. package/packages/ui/src/components/util/storage.ts +37 -0
  177. package/packages/ui/src/globals.css +87 -0
  178. package/packages/ui/tailwind.config.ts +94 -0
  179. package/packages/ui/tsconfig.json +12 -0
  180. package/pnpm-workspace.yaml +43 -0
  181. 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,8 @@
1
+ {
2
+ "extends": "typescript-config/tsconfig.node.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./src"
5
+ },
6
+
7
+ "include": ["src/**/*.ts", "vitest.config.ts", "plugins.d.ts"]
8
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from "tsdown";
2
+ import { baseConfig } from "tsdown-config";
3
+
4
+ export default defineConfig({
5
+ ...baseConfig,
6
+ unbundle: false,
7
+ clean:false,
8
+ entry: [
9
+ "./src/**/*.ts",
10
+ ],
11
+ });
@@ -0,0 +1,3 @@
1
+ import vitestConfig from "vitest-config/node";
2
+
3
+ export default vitestConfig;
@@ -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,10 @@
1
+ {
2
+ "name": "typescript-config",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "files": [
6
+ "tsconfig.common.json",
7
+ "tsconfig.frontend.json",
8
+ "tsconfig.node.json"
9
+ ]
10
+ }
@@ -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
+ }