velocious 1.0.85 → 1.0.87

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 (95) hide show
  1. package/bin/velocious.js +10 -1
  2. package/eslint.config.js +33 -0
  3. package/package.json +7 -2
  4. package/peak_flow.yml +6 -0
  5. package/spec/cli/commands/db/create-spec.js +4 -0
  6. package/spec/cli/commands/db/migrate-spec.js +4 -2
  7. package/spec/cli/commands/db/rollback-spec.js +179 -0
  8. package/spec/cli/commands/destroy/migration-spec.js +4 -0
  9. package/spec/cli/commands/generate/migration-spec.js +4 -0
  10. package/spec/cli/commands/init-spec.js +4 -0
  11. package/spec/dummy/index.js +7 -4
  12. package/spec/dummy/src/config/configuration.example.js +2 -0
  13. package/spec/dummy/src/config/configuration.peakflow.mariadb.js +2 -0
  14. package/spec/dummy/src/config/configuration.peakflow.mssql.js +2 -0
  15. package/spec/dummy/src/config/configuration.peakflow.pgsql.js +2 -0
  16. package/spec/dummy/src/config/configuration.peakflow.sqlite.js +2 -0
  17. package/spec/dummy/src/database/migrations/20250921121002-create-project-details.js +3 -1
  18. package/src/application.js +12 -0
  19. package/src/cli/base-command.js +9 -5
  20. package/src/cli/browser-cli.js +37 -0
  21. package/src/cli/commands/db/create.js +5 -5
  22. package/src/cli/commands/db/drop.js +4 -5
  23. package/src/cli/commands/db/migrate.js +6 -10
  24. package/src/cli/commands/db/reset.js +8 -12
  25. package/src/cli/commands/db/rollback.js +15 -0
  26. package/src/cli/commands/destroy/migration.js +2 -2
  27. package/src/cli/commands/generate/migration.js +3 -6
  28. package/src/cli/commands/generate/model.js +3 -6
  29. package/src/cli/commands/init.js +5 -8
  30. package/src/cli/commands/server.js +3 -3
  31. package/src/cli/commands/test.js +1 -1
  32. package/src/cli/index.js +15 -63
  33. package/src/cli/use-browser-cli.js +25 -0
  34. package/src/configuration-resolver.js +1 -1
  35. package/src/configuration.js +118 -9
  36. package/src/controller.js +29 -0
  37. package/src/database/drivers/base-column.js +14 -0
  38. package/src/database/drivers/base-columns-index.js +3 -0
  39. package/src/database/drivers/base-foreign-key.js +3 -0
  40. package/src/database/drivers/base-table.js +3 -0
  41. package/src/database/drivers/base.js +55 -1
  42. package/src/database/drivers/mssql/index.js +64 -1
  43. package/src/database/drivers/mysql/columns-index.js +0 -1
  44. package/src/database/drivers/sqlite/base.js +39 -0
  45. package/src/database/drivers/sqlite/connection-remote.js +1 -1
  46. package/src/database/drivers/sqlite/sql/alter-table.js +1 -1
  47. package/src/database/drivers/sqlite/sql/delete.js +15 -10
  48. package/src/database/migration/index.js +122 -1
  49. package/src/database/migrator/files-finder.js +13 -1
  50. package/src/database/migrator.js +125 -24
  51. package/src/database/pool/single-multi-use.js +1 -1
  52. package/src/database/query/alter-table-base.js +11 -0
  53. package/src/database/query/base.js +7 -0
  54. package/src/database/query/create-database-base.js +3 -0
  55. package/src/database/query/create-index-base.js +3 -1
  56. package/src/database/query/create-table-base.js +3 -0
  57. package/src/database/query/drop-table-base.js +4 -1
  58. package/src/database/query/from-base.js +7 -0
  59. package/src/database/query/index.js +96 -6
  60. package/src/database/query/insert-base.js +6 -0
  61. package/src/database/query/join-base.js +3 -0
  62. package/src/database/query/order-base.js +3 -0
  63. package/src/database/query/select-base.js +3 -0
  64. package/src/database/query/update-base.js +3 -0
  65. package/src/database/query/where-base.js +3 -0
  66. package/src/database/record/index.js +272 -19
  67. package/src/database/record/instance-relationships/base.js +66 -1
  68. package/src/database/record/relationships/base.js +41 -1
  69. package/src/database/record/validators/base.js +10 -0
  70. package/src/database/record/validators/presence.js +1 -1
  71. package/src/database/table-data/table-column.js +37 -3
  72. package/src/database/table-data/table-index.js +1 -1
  73. package/src/database/use-database.js +2 -2
  74. package/src/environment-handlers/base.js +53 -0
  75. package/src/environment-handlers/browser.js +171 -0
  76. package/src/environment-handlers/node.js +162 -0
  77. package/src/http-server/client/request-buffer/index.js +9 -9
  78. package/src/http-server/index.js +6 -0
  79. package/src/http-server/worker-handler/index.js +20 -19
  80. package/src/initializer.js +17 -1
  81. package/src/logger.js +3 -0
  82. package/src/routes/app-routes.js +6 -2
  83. package/src/routes/base-route.js +1 -1
  84. package/src/routes/get-route.js +1 -1
  85. package/src/routes/namespace-route.js +1 -1
  86. package/src/routes/post-route.js +1 -1
  87. package/src/routes/resolver.js +1 -1
  88. package/src/routes/resource-route.js +1 -1
  89. package/src/templates/configuration.js +4 -0
  90. package/src/testing/request-client.js +26 -3
  91. package/src/testing/test-files-finder.js +2 -2
  92. package/src/testing/test-runner.js +74 -28
  93. package/src/testing/test.js +62 -0
  94. package/src/utils/file-exists.js +7 -5
  95. package/src/utils/rest-args-error.js +5 -3
@@ -40,17 +40,17 @@ export default class RequestBuffer {
40
40
 
41
41
  break
42
42
  case "multi-part-form-data-body":
43
- const body = this.formDataPart.body
43
+ const body = this.formDataPart.body // eslint-disable-line no-case-declarations
44
44
 
45
45
  body.push(char)
46
46
 
47
- const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length
48
- const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length)
49
- const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars)
47
+ const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length // eslint-disable-line no-case-declarations
48
+ const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length) // eslint-disable-line no-case-declarations
49
+ const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars) // eslint-disable-line no-case-declarations
50
50
 
51
- const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length
52
- const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length)
53
- const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars)
51
+ const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length // eslint-disable-line no-case-declarations
52
+ const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length) // eslint-disable-line no-case-declarations
53
+ const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars) // eslint-disable-line no-case-declarations
54
54
 
55
55
  if (possibleBoundaryEnd == this.boundaryLineEnd) {
56
56
  this.formDataPart.removeFromBody(possibleBoundaryEnd)
@@ -150,9 +150,9 @@ export default class RequestBuffer {
150
150
  }
151
151
 
152
152
  readHeaderFromLine(line) {
153
- let match
153
+ const match = line.match(/^(.+): (.+)\r\n/)
154
154
 
155
- if (match = line.match(/^(.+): (.+)\r\n/)) {
155
+ if (match) {
156
156
  const header = new Header(match[1], match[2])
157
157
 
158
158
  return header
@@ -20,6 +20,9 @@ export default class VelociousHttpServer {
20
20
  this.maxWorkers = maxWorkers || 16
21
21
  }
22
22
 
23
+ /**
24
+ * @returns {Promise<void>}
25
+ */
23
26
  async start() {
24
27
  await this._ensureAtLeastOneWorker()
25
28
  this.netServer = new Net.Server()
@@ -47,6 +50,9 @@ export default class VelociousHttpServer {
47
50
  }
48
51
  }
49
52
 
53
+ /**
54
+ * @returns {boolean}
55
+ */
50
56
  isActive() {
51
57
  return this.netServer.listening
52
58
  }
@@ -1,6 +1,4 @@
1
1
  import {digg, digs} from "diggerize"
2
- import {dirname} from "path"
3
- import {fileURLToPath} from "url"
4
2
  import {Logger} from "../../logger.js"
5
3
  import {Worker} from "worker_threads"
6
4
 
@@ -12,26 +10,29 @@ export default class VelociousHttpServerWorker {
12
10
  this.workerCount = workerCount
13
11
  }
14
12
 
15
- async start() {
13
+ start() {
16
14
  return new Promise((resolve) => {
17
- const {debug} = digs(this.configuration, "debug")
18
- const directory = this.configuration.getDirectory()
19
- const __filename = fileURLToPath(import.meta.url)
20
- const __dirname = dirname(__filename)
21
-
22
15
  this.onStartCallback = resolve
23
- this.worker = new Worker(`${__dirname}/worker-script.js`, {
24
- workerData: {
25
- debug,
26
- directory,
27
- environment: this.configuration.getEnvironment(),
28
- workerCount: this.workerCount
29
- }
30
- })
31
- this.worker.on("error", this.onWorkerError)
32
- this.worker.on("exit", this.onWorkerExit)
33
- this.worker.on("message", this.onWorkerMessage)
16
+ this._spawnWorker()
17
+ })
18
+ }
19
+
20
+ async _spawnWorker() {
21
+ const {debug} = digs(this.configuration, "debug")
22
+ const directory = this.configuration.getDirectory()
23
+ const velociousPath = await this.configuration.getEnvironmentHandler().getVelociousPath()
24
+
25
+ this.worker = new Worker(`${velociousPath}/src/http-server/worker-handler/worker-script.js`, {
26
+ workerData: {
27
+ debug,
28
+ directory,
29
+ environment: this.configuration.getEnvironment(),
30
+ workerCount: this.workerCount
31
+ }
34
32
  })
33
+ this.worker.on("error", this.onWorkerError)
34
+ this.worker.on("exit", this.onWorkerExit)
35
+ this.worker.on("message", this.onWorkerMessage)
35
36
  }
36
37
 
37
38
  addSocketConnection(client) {
@@ -1,10 +1,26 @@
1
+ import restArgsError from "./utils/rest-args-error.js"
2
+
1
3
  export default class VelociousInitializer {
2
- constructor({configuration, type}) {
4
+ /**
5
+ * @param {object} args
6
+ * @param {import("./configuration.js").default} args.configuration
7
+ * @param {string} args.type
8
+ */
9
+ constructor({configuration, type, ...restArgs}) {
10
+ restArgsError(restArgs)
11
+
3
12
  this._configuration = configuration
4
13
  this._type = type
5
14
  }
6
15
 
16
+ /**
17
+ * @returns {import("./configuration.js").default}
18
+ */
7
19
  getConfiguration() { return this._configuration }
20
+
21
+ /**
22
+ * @returns {string}
23
+ */
8
24
  getType() { return this._type }
9
25
 
10
26
  run() {
package/src/logger.js CHANGED
@@ -74,6 +74,9 @@ class Logger {
74
74
  }
75
75
  }
76
76
 
77
+ /**
78
+ * @returns {import("./configuration.js").default}
79
+ */
77
80
  getConfiguration() {
78
81
  if (!this._configuration) {
79
82
  this._configuration = this._object?.configuration || Configuration.current()
@@ -1,10 +1,14 @@
1
1
  import {digg} from "diggerize"
2
2
 
3
3
  export default class VelociousRoutesAppRoutes {
4
+ /**
5
+ * @param {import("../configuration.js")} configuration
6
+ * @returns {import("./index.js").default}
7
+ */
4
8
  static async getRoutes(configuration) {
5
9
  // Every client need to make their own routes because they probably can't be shared across different worker threads
6
- const routesImport = await import(`${configuration.getDirectory()}/src/config/routes.js`)
10
+ const routesImport = await configuration.getEnvironmentHandler().importApplicationRoutes()
7
11
 
8
- return digg(routesImport, "default", "routes")
12
+ return digg(routesImport, "routes")
9
13
  }
10
14
  }
@@ -17,7 +17,7 @@ export function initBaseRoute() {
17
17
  this.routes.push(route)
18
18
  }
19
19
 
20
- matchWithPath(_path) {
20
+ matchWithPath(_path) { // eslint-disable-line no-unused-vars
21
21
  throw new Error(`No 'matchWithPath' implemented on ${this.constructor.name}`)
22
22
  }
23
23
 
@@ -14,7 +14,7 @@ export default class VelociousRouteGetRoute extends BaseRoute {
14
14
  const match = path.match(this.regExp)
15
15
 
16
16
  if (match) {
17
- const [_beginnigSlash, _matchedName, restPath] = match
17
+ const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
18
18
 
19
19
  params.action = this.name
20
20
 
@@ -14,7 +14,7 @@ export default class VelociousRouteNamespaceRoute extends BaseRoute {
14
14
  const match = path.match(this.regExp)
15
15
 
16
16
  if (match) {
17
- const [_beginnigSlash, _matchedName, restPath] = match
17
+ const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
18
18
 
19
19
  params.controller = this.name
20
20
 
@@ -14,7 +14,7 @@ export default class VelociousRoutePostRoute extends BaseRoute {
14
14
  const match = path.match(this.regExp)
15
15
 
16
16
  if (match) {
17
- const [_beginnigSlash, _matchedName, restPath] = match
17
+ const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
18
18
 
19
19
  params.action = this.name
20
20
 
@@ -33,7 +33,7 @@ export default class VelociousRoutesResolver {
33
33
  controller = "errors"
34
34
  controllerPath = "./built-in/errors/controller.js"
35
35
  action = "notFound"
36
- viewPath = await fs.realpath(`${__dirname}/built-in/errors`) // eslint-disable-line no-undef
36
+ viewPath = await fs.realpath(`${__dirname}/built-in/errors`)
37
37
  } else if (action) {
38
38
  if (!controller) controller = "_root"
39
39
 
@@ -14,7 +14,7 @@ export default class VelociousRouteResourceRoute extends BaseRoute {
14
14
  const match = path.match(this.regExp)
15
15
 
16
16
  if (match) {
17
- const [_beginnigSlash, _matchedName, restPath] = match
17
+ const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
18
18
 
19
19
  let action = "index"
20
20
  let subRoutesMatchesRestPath = false
@@ -1,6 +1,10 @@
1
1
  import AsyncTrackedMultiConnection from "velocious/src/database/pool/async-tracked-multi-connection.js"
2
2
  import Configuration from "velocious/src/configuration.js"
3
+ import fs from "fs/promises"
4
+ import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.js"
3
5
  import MysqlDriver from "velocious/src/database/drivers/mysql/index.js"
6
+ import path from "path"
7
+ import requireContext from "require-context"
4
8
 
5
9
  export default new Configuration({
6
10
  database: {
@@ -3,21 +3,39 @@ class Response {
3
3
  this.fetchResponse = fetchResponse
4
4
  }
5
5
 
6
+ /**
7
+ * @returns {void}
8
+ */
6
9
  async parse() {
7
10
  this._body = await this.fetchResponse.text()
8
11
 
9
12
  if (this.statusCode() != 200) throw new Error(`Request failed with code ${this.statusCode()} and body: ${this.body()}`)
10
13
  }
11
14
 
12
- body = () => this._body
13
- contentType = () => this.fetchResponse.headers.get("content-type")
14
- statusCode = () => this.fetchResponse.status
15
+ /**
16
+ * @returns {string}
17
+ */
18
+ body() { return this._body }
19
+
20
+ /**
21
+ * @returns {string}
22
+ */
23
+ contentType() { return this.fetchResponse.headers.get("content-type") }
24
+
25
+ /**
26
+ * @returns {string}
27
+ */
28
+ statusCode() { return this.fetchResponse.status }
15
29
  }
16
30
 
17
31
  export default class RequestClient {
18
32
  host = "localhost"
19
33
  port = 31006
20
34
 
35
+ /**
36
+ * @param {string} path
37
+ * @returns {Response}
38
+ */
21
39
  async get(path) {
22
40
  const fetchResponse = await fetch(`http://${this.host}:${this.port}${path}`)
23
41
  const response = new Response(fetchResponse)
@@ -27,6 +45,11 @@ export default class RequestClient {
27
45
  return response
28
46
  }
29
47
 
48
+ /**
49
+ * @param {string} path
50
+ * @param {object} data
51
+ * @returns {Response}
52
+ */
30
53
  async post(path, data) {
31
54
  const fetchResponse = await fetch(
32
55
  `http://${this.host}:${this.port}${path}`,
@@ -75,7 +75,7 @@ export default class TestFilesFinder {
75
75
  if (isDir) {
76
76
  this.findTestFilesInDir(fullPath)
77
77
  } else {
78
- if (this.isFileMatchingRequirements(file, localPath, fullPath)) {
78
+ if (this.isFileMatchingRequirements(file, localPath)) {
79
79
  this.foundFiles.push(fullPath)
80
80
  }
81
81
  }
@@ -83,7 +83,7 @@ export default class TestFilesFinder {
83
83
  })
84
84
  }
85
85
 
86
- isFileMatchingRequirements(file, localPath, fullPath) {
86
+ isFileMatchingRequirements(file, localPath) {
87
87
  if (this.testArgs.length > 0) {
88
88
  for (const testArg of this.testArgs) {
89
89
  if (testArg == localPath) {
@@ -2,18 +2,41 @@ import {addTrackedStackToError} from "../utils/with-tracked-stack.js"
2
2
  import Application from "../../src/application.js"
3
3
  import BacktraceCleaner from "../utils/backtrace-cleaner.js"
4
4
  import RequestClient from "./request-client.js"
5
+ import restArgsError from "../utils/rest-args-error.js"
5
6
  import {tests} from "./test.js"
6
7
 
7
8
  export default class TestRunner {
8
- constructor({configuration, testFiles}) {
9
- this.configuration = configuration
10
- this.testFiles = testFiles
9
+ /**
10
+ * @param {object} args
11
+ * @param {import("../configuration.js").default} args.configuration
12
+ * @param {Array<string>} args.testFiles
13
+ */
14
+ constructor({configuration, testFiles, ...restArgs}) {
15
+ restArgsError(restArgs)
16
+
17
+ if (!configuration) throw new Error("configuration is required")
18
+
19
+ this._configuration = configuration
20
+ this._testFiles = testFiles
11
21
  }
12
22
 
23
+ /**
24
+ * @returns {import("../configuration.js").default}
25
+ */
26
+ getConfiguration() { return this._configuration }
27
+
28
+ /**
29
+ * @returns {Array<string>}
30
+ */
31
+ getTestFiles() { return this._testFiles }
32
+
33
+ /**
34
+ * @returns {Promise<Application>}
35
+ */
13
36
  async application() {
14
37
  if (!this._application) {
15
38
  this._application = new Application({
16
- configuration: this.configuration,
39
+ configuration: this.getConfiguration(),
17
40
  databases: {
18
41
  default: {
19
42
  host: "mysql",
@@ -32,6 +55,9 @@ export default class TestRunner {
32
55
  return this._application
33
56
  }
34
57
 
58
+ /**
59
+ * @returns {RequestClient}
60
+ */
35
61
  async requestClient() {
36
62
  if (!this._requestClient) {
37
63
  this._requestClient = new RequestClient()
@@ -40,28 +66,36 @@ export default class TestRunner {
40
66
  return this._requestClient
41
67
  }
42
68
 
69
+ /**
70
+ * @returns {void}
71
+ */
43
72
  async importTestFiles() {
44
- for (const testFile of this.testFiles) {
45
- await import(testFile)
46
- }
47
- }
48
-
49
- isFailed() {
50
- return this._failedTests > 0
51
- }
52
-
53
- getFailedTests() {
54
- return this._failedTests
55
- }
56
-
57
- getSuccessfulTests() {
58
- return this._successfulTests
59
- }
60
-
61
- getTestsCount() {
62
- return this._testsCount
73
+ await this.getConfiguration().getEnvironmentHandler().importTestFiles(this.getTestFiles())
63
74
  }
64
75
 
76
+ /**
77
+ * @returns {boolean}
78
+ */
79
+ isFailed() { return this._failedTests > 0 }
80
+
81
+ /**
82
+ * @returns {number}
83
+ */
84
+ getFailedTests() { return this._failedTests }
85
+
86
+ /**
87
+ * @returns {number}
88
+ */
89
+ getSuccessfulTests() { return this._successfulTests }
90
+
91
+ /**
92
+ * @returns {number}
93
+ */
94
+ getTestsCount() { return this._testsCount }
95
+
96
+ /**
97
+ * @returns {void}
98
+ */
65
99
  async prepare() {
66
100
  this.anyTestsFocussed = false
67
101
  this._failedTests = 0
@@ -71,13 +105,16 @@ export default class TestRunner {
71
105
  await this.analyzeTests(tests)
72
106
  this._onlyFocussed = this.anyTestsFocussed
73
107
 
74
- const testingConfigPath = this.configuration.getTesting()
108
+ const testingConfigPath = this.getConfiguration().getTesting()
75
109
 
76
110
  if (testingConfigPath) {
77
- await import(testingConfigPath)
111
+ await this.getConfiguration().getEnvironmentHandler().importTestingConfigPath()
78
112
  }
79
113
  }
80
114
 
115
+ /**
116
+ * @returns {boolean}
117
+ */
81
118
  areAnyTestsFocussed() {
82
119
  if (this.anyTestsFocussed === undefined) {
83
120
  throw new Error("Hasn't been detected yet")
@@ -86,8 +123,11 @@ export default class TestRunner {
86
123
  return this.anyTestsFocussed
87
124
  }
88
125
 
126
+ /**
127
+ * @returns {void}
128
+ */
89
129
  async run() {
90
- await this.configuration.ensureConnections(async () => {
130
+ await this.getConfiguration().ensureConnections(async () => {
91
131
  await this.runTests({
92
132
  afterEaches: [],
93
133
  beforeEaches: [],
@@ -98,6 +138,9 @@ export default class TestRunner {
98
138
  })
99
139
  }
100
140
 
141
+ /**
142
+ * @returns {object}
143
+ */
101
144
  analyzeTests(tests) {
102
145
  let anyTestsFocussedFound = false
103
146
 
@@ -127,6 +170,9 @@ export default class TestRunner {
127
170
  return {anyTestsFocussed: anyTestsFocussedFound}
128
171
  }
129
172
 
173
+ /**
174
+ * @returns {Promise<void>}
175
+ */
130
176
  async runTests({afterEaches, beforeEaches, tests, descriptions, indentLevel}) {
131
177
  const leftPadding = " ".repeat(indentLevel * 2)
132
178
  const newAfterEaches = [...afterEaches, ...tests.afterEaches]
@@ -150,7 +196,7 @@ export default class TestRunner {
150
196
 
151
197
  try {
152
198
  for (const beforeEachData of newBeforeEaches) {
153
- await beforeEachData.callback({configuration: this.configuration, testArgs, testData})
199
+ await beforeEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
154
200
  }
155
201
 
156
202
  await testData.function(testArgs)
@@ -170,7 +216,7 @@ export default class TestRunner {
170
216
  }
171
217
  } finally {
172
218
  for (const afterEachData of newAfterEaches) {
173
- await afterEachData.callback({configuration: this.configuration, testArgs, testData})
219
+ await afterEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
174
220
  }
175
221
  }
176
222
  }
@@ -31,6 +31,9 @@ class ExpectToChange {
31
31
  this.changeCallback = changeCallback
32
32
  }
33
33
 
34
+ /**
35
+ * @returns {Expect}
36
+ */
34
37
  by(count) {
35
38
  this.count = count
36
39
 
@@ -60,16 +63,25 @@ class Expect {
60
63
  this.expectations = []
61
64
  }
62
65
 
66
+ /**
67
+ * @returns {ExpectToChange}
68
+ */
63
69
  andChange(...args) {
64
70
  return this.toChange(...args)
65
71
  }
66
72
 
73
+ /**
74
+ * @returns {this}
75
+ */
67
76
  get not() {
68
77
  this._not = true
69
78
 
70
79
  return this
71
80
  }
72
81
 
82
+ /**
83
+ * @returns {void}
84
+ */
73
85
  toBe(result) {
74
86
  if (this._not) {
75
87
  if (this._object === result) {
@@ -82,6 +94,9 @@ class Expect {
82
94
  }
83
95
  }
84
96
 
97
+ /**
98
+ * @returns {void}
99
+ */
85
100
  toBeDefined() {
86
101
  if (this._not) {
87
102
  if (this._object !== undefined) {
@@ -94,24 +109,40 @@ class Expect {
94
109
  }
95
110
  }
96
111
 
112
+ /**
113
+ * @returns {void}
114
+ */
97
115
  toBeInstanceOf(klass) {
98
116
  if (!(this._object instanceof klass)) {
99
117
  throw new Error(`Expected ${this._object?.constructor?.name || "null"} to be a ${klass.name} but it wasn't`)
100
118
  }
101
119
  }
102
120
 
121
+ /**
122
+ * @returns {void}
123
+ */
103
124
  toBeFalse() {
104
125
  this.toBe(false)
105
126
  }
106
127
 
128
+ /**
129
+ * @returns {void}
130
+ */
107
131
  toBeUndefined() {
108
132
  this.toBe(undefined)
109
133
  }
110
134
 
135
+ /**
136
+ * @returns {void}
137
+ */
111
138
  toBeTrue() {
112
139
  this.toBe(true)
113
140
  }
114
141
 
142
+ /**
143
+ * @param {function(): void} changeCallback
144
+ * @returns {ExpectToChange}
145
+ */
115
146
  toChange(changeCallback) {
116
147
  if (this._not) throw new Error("not stub")
117
148
 
@@ -122,6 +153,9 @@ class Expect {
122
153
  return expectToChange
123
154
  }
124
155
 
156
+ /**
157
+ * @returns {void}
158
+ */
125
159
  toContain(valueToContain) {
126
160
  if (this._not) throw new Error("not stub")
127
161
 
@@ -130,6 +164,9 @@ class Expect {
130
164
  }
131
165
  }
132
166
 
167
+ /**
168
+ * @returns {void}
169
+ */
133
170
  toEqual(result) {
134
171
  if (this._not) {
135
172
  if (typeof this._object == "object" && typeof result == "object") {
@@ -154,6 +191,9 @@ class Expect {
154
191
  }
155
192
  }
156
193
 
194
+ /**
195
+ * @returns {void}
196
+ */
157
197
  toMatch(regex) {
158
198
  const match = this._object.match(regex)
159
199
 
@@ -168,6 +208,9 @@ class Expect {
168
208
  }
169
209
  }
170
210
 
211
+ /**
212
+ * @returns {void}
213
+ */
171
214
  async toThrowError(expectedError) {
172
215
  if (this._not) throw new Error("not stub")
173
216
 
@@ -218,6 +261,10 @@ class Expect {
218
261
  return result
219
262
  }
220
263
 
264
+ /**
265
+ * @param {object} result
266
+ * @returns {void}
267
+ */
221
268
  toHaveAttributes(result) {
222
269
  if (this._not) throw new Error("not stub")
223
270
 
@@ -241,6 +288,10 @@ class Expect {
241
288
  }
242
289
  }
243
290
 
291
+ /**
292
+ * @param {string} description
293
+ * @returns {void}
294
+ */
244
295
  async function describe(description, arg1, arg2) {
245
296
  let testArgs, testFunction
246
297
 
@@ -273,10 +324,17 @@ async function describe(description, arg1, arg2) {
273
324
  }
274
325
  }
275
326
 
327
+ /**
328
+ * @returns {Expect}
329
+ */
276
330
  function expect(arg) {
277
331
  return new Expect(arg)
278
332
  }
279
333
 
334
+ /**
335
+ * @param {string} description
336
+ * @returns {void}
337
+ */
280
338
  function it(description, arg1, arg2) {
281
339
  const currentTest = currentPath[currentPath.length - 1]
282
340
  let testArgs, testFunction
@@ -296,6 +354,10 @@ function it(description, arg1, arg2) {
296
354
  currentTest.tests[description] = {args: newTestArgs, function: testFunction}
297
355
  }
298
356
 
357
+ /**
358
+ * @param {string} description
359
+ * @returns {void}
360
+ */
299
361
  function fit(description, arg1, arg2) {
300
362
  let testArgs, testFunction
301
363
 
@@ -1,13 +1,15 @@
1
- import fs from "node:fs/promises"
1
+ import fs from "fs/promises"
2
2
 
3
- async function fileExists(path) {
3
+ /**
4
+ * @param {string} path
5
+ * @returns {boolean}
6
+ */
7
+ export default async function fileExists(path) {
4
8
  try {
5
9
  await fs.access(path)
6
10
 
7
11
  return true
8
- } catch (error) {
12
+ } catch (error) { // eslint-disable-line no-unused-vars
9
13
  return false
10
14
  }
11
15
  }
12
-
13
- export default fileExists