-
Notifications
You must be signed in to change notification settings - Fork 1
feat: use prettier, oxlint and vitest #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis update migrates the project's linting, formatting, and testing toolchain from ESLint, Egg-Bin, and Mocha to OXLint, Prettier, and Vitest. It removes the ESLint configuration, introduces OXLint and Prettier configs, updates scripts and dependencies, and refactors code and tests for improved style, type safety, and compatibility with the new tools. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer
participant Git as Git (with Husky)
participant Lint as OXLint/Prettier
participant Test as Vitest
participant CI as GitHub Actions
Dev->>Git: git commit
Git->>Lint: Run lint-staged (OXLint, Prettier) on staged files
Lint-->>Git: Lint passes or fails
Git->>Dev: Commit proceeds or aborts
Dev->>CI: Push to repository
CI->>Lint: Run OXLint on codebase
CI->>Test: Run Vitest with coverage
Test->>CI: Test results and coverage
CI->>Dev: CI status (pass/fail)
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms (4)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new code style and quality workflow by integrating prettier, oxlint, and vitest while refactoring several modules for improved readability and maintainability. Key changes include reformatting functions into multi‐line signatures, standardizing assertions (using assert.ok), updating configuration files, and adjusting type declarations and error handling.
Reviewed Changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/util/sign.ts | Refactored function signatures and loop iterations for clarity. |
| src/util/policyToJSONString.ts | Improved error message handling for JSON parsing. |
| src/util/json2xml.ts | Updated type annotations and recursive call formatting. |
| src/util/encodeCallback.ts | Adjusted formatting for base64 conversion, improving readability. |
| src/util/checkObjectTag.ts | Simplified condition structure and error messages. |
| src/util/checkBucketName.ts | Reformatted regex condition for bucket name validation. |
| src/type/* | Updated union types’ formatting and multiline declarations. |
| src/OSSObject.ts | Converted assertions to assert.ok, clarified overloads & mappings. |
| src/OSSBaseClient.ts | Improved assertion messaging and updated internal request logic. |
| package.json & config files | Updated dependencies & scripts to use prettier, oxlint, vitest, husky. |
| .github/workflows/nodejs.yml | Updated Node versions and Codecov action version. |
| README.md | Adjusted API usage examples to improved formatting. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (4)
.husky/pre-commit (1)
1-2:⚠️ Potential issueMissing Husky hook initialization
Husky requires sourcing its runner script before commands. Without it, the hook may not run.Apply this diff:
+#!/usr/bin/env sh +. "$(dirname "$0")/_/husky.sh" npx lint-stagedtest/OSSObject.test.ts (1)
1486-1486:⚠️ Potential issueFix timeout in traffic limit test.
The test "should signature url with traffic limit" is timing out in 5000ms, which is causing build failures:
Test timed out in 5000ms for 'should signature url with traffic limit'. Consider increasing timeout with 'testTimeout' option.Increase the test timeout specifically for this test:
- it('should signature url with traffic limit', async () => { + it('should signature url with traffic limit', async () => { + // This test involves network operations that may take longer than the default timeout + vi.setConfig({ testTimeout: 30000 });Or use the testTimeout option in the test declaration:
- it('should signature url with traffic limit', async () => { + it('should signature url with traffic limit', { timeout: 30000 }, async () => {🧰 Tools
🪛 GitHub Check: build (24, ubuntu-latest)
[failure] 1486-1486: test/OSSObject.test.ts > test/OSSObject.test.ts > signatureUrl() and asyncSignatureUrl() > should signature url with traffic limit
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ test/OSSObject.test.ts:1486:5🪛 GitHub Check: build (20, ubuntu-latest)
[failure] 1486-1486: test/OSSObject.test.ts > test/OSSObject.test.ts > signatureUrl() and asyncSignatureUrl() > should signature url with traffic limit
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ test/OSSObject.test.ts:1486:5🪛 GitHub Check: build (18, ubuntu-latest)
[failure] 1486-1486: test/OSSObject.test.ts > test/OSSObject.test.ts > signatureUrl() and asyncSignatureUrl() > should signature url with traffic limit
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ test/OSSObject.test.ts:1486:5🪛 GitHub Check: build (22, ubuntu-latest)
[failure] 1486-1486: test/OSSObject.test.ts > test/OSSObject.test.ts > signatureUrl() and asyncSignatureUrl() > should signature url with traffic limit
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
❯ test/OSSObject.test.ts:1486:5🪛 GitHub Actions: Node.js CI
[error] 1486-1486: Test timed out in 5000ms for 'should signature url with traffic limit'. Consider increasing timeout with 'testTimeout' option.
src/util/sign.ts (1)
32-40:⚠️ Potential issueCanonicalization sort only compares first character – breaks signature for multi-char keys
compareFuncreturns a result based solely onentry[0], so keys like"abc"and"az"are treated as equal.
When OSS validates the signature it expects keys to be sorted by the full string; a wrong order yieldsSignatureDoesNotMatch.-const compareFunc = (entry1: string, entry2: string) => { - if (entry1[0] > entry2[0]) { - return 1; - } else if (entry1[0] < entry2[0]) { - return -1; - } - return 0; -}; +const compareFunc = (a: string, b: string) => (a > b ? 1 : a < b ? -1 : 0);This keeps the original intent but performs a full lexical comparison.
Also applies to: 47-49
src/OSSObject.ts (1)
384-388:⚠️ Potential issueDestroying the write stream immediately causes “ERR_STREAM_UNABLE_TO_PIPE”
CI shows failures (
Cannot pipe to a closed or destroyed stream) in tests that pass a file path toget().
urllibresolves the promise when the response ends, not when thewriteStreamfinishes flushing.
CallingwriteStream.destroy()at this point closes the FD early and triggers the error.- if (needDestroy && writeStream) { - writeStream.destroy(); - } + // Wait for the stream to flush before closing it + if (needDestroy && writeStream) { + await new Promise<void>(resolve => { + writeStream.once('close', resolve); + }); + }This lets the OS flush and close the descriptor safely, removing the pipeline failure.
🧹 Nitpick comments (10)
test/util/isIP.test.ts (1)
3-3: Optional: Adopt Vitest'sexpectAPI.
Consider importing and using Vitest'sexpectfor assertions (expect(isIP(...)).toBe(true)) to leverage built-in matchers and improve readability.src/util/checkBucketName.ts (1)
5-6: Nitpick: Improve error message grammar.
Change the error message from:'The bucket must be conform to the specifications'to:
'The bucket must conform to the specifications'src/util/encodeCallback.ts (1)
20-22: Optional: Extract base64 encoding to helper.
Consider defining a helper such as:function toBase64(obj: unknown): string { return Buffer.from(JSON.stringify(obj)).toString('base64'); }to reduce duplication and centralize encoding logic.
Also applies to: 32-34
src/util/checkObjectTag.ts (2)
8-10: Grammar refinement in error message
The message reads “maximum of 10 tags for a object” but should use “an object.”Proposed diff:
- throw new TypeError('maximum of 10 tags for a object'); + throw new TypeError('maximum of 10 tags for an object');
12-14: Grammar refinement in error message
Use plural “strings” and lowercase for consistency.Proposed diff:
- throw new TypeError('the key and value of the tag must be String'); + throw new TypeError('the key and value of the tag must be strings');src/util/json2xml.ts (1)
4-5: Optional refactor: extractoptionsinterface
If you expect more flags later, consider:interface Json2XmlOptions { headers?: boolean } export function json2xml( json: Record<string, unknown>, options?: Json2XmlOptions )README.md (1)
1-1658: Approve documentation formatting changes
Prettier has reformatted code snippets, lists, and tables without altering any API descriptions or examples.Grammar nitpick in
.deleteMultidescription
Fix typo “succes” → “success”, add missing comma/semicolon.- quiet mode: if all objects delete succes, return emtpy response. otherwise return delete error object results. + quiet mode: if all objects delete successfully, return empty response; otherwise, return delete error object results.🧰 Tools
🪛 LanguageTool
[uncategorized] ~26-~26: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... OSS, Object Storage Service. Equal to well known Amazon S3....(EN_COMPOUND_ADJECTIVE_INTERNAL)
[grammar] ~146-~146: An article may be missing.
Context: ... aliyun too, you can settrueto save lot of money. - [timeout] {String|Number} inst...(BUNCH_OF)
[grammar] ~166-~166: There seems to be a noun/verb agreement error. Did you mean “accelerates” or “accelerated”?
Context: ...ion: 'oss-cn-hangzhou', }); ``` 2. use accelerate endpoint - Global accelerate endpoint:...(SINGULAR_NOUN_VERB_AGREEMENT)
[uncategorized] ~405-~405: Possible missing article found.
Context: ...nd an object to the bucket, it's almost same as put, but it can add content to exist...(AI_HYDRA_LEO_MISSING_THE)
[uncategorized] ~405-~405: Possible missing article found.
Context: ... same as put, but it can add content to existing object rather than override it. All pa...(AI_HYDRA_LEO_MISSING_AN)
[uncategorized] ~448-~448: Possible missing preposition found.
Context: ...ebaseUrl, will usebaseUrlinstead the defaultbucket and endpoint. Suggest ...(AI_HYDRA_LEO_MISSING_OF)
[grammar] ~550-~550: Possible subject-verb agreement error.
Context: ... example: - Head an exists object and get object meta info ```js await this.stor...(IS_AND_ARE)
[grammar] ~718-~718: In standard English, the word ‘exists’ is a verb. Please verify that the determiner ‘an’ is correct, or that a noun is not missing between ‘an’ and ‘exists’.
Context: ...lso delete success. example: - Delete an exists object ```js await store.delete('ossde...(A_INFINITIVE)
[grammar] ~745-~745: It seems that a pronoun is missing.
Context: ... [sourceBucket] {String} source Bucket. if doesn't exist,sourceBucketis same bu...(IF_VB)
[grammar] ~745-~745: Is an article like ‘a’ or ‘an’ missing?
Context: ...Bucket. if doesn't exist,sourceBucketis same bucket. - [options] {Object} optio...(BE_NN)
[uncategorized] ~745-~745: Possible missing article found.
Context: ...ket. if doesn't exist,sourceBucketis same bucket. - [options] {Object} optional p...(AI_HYDRA_LEO_MISSING_THE)
[grammar] ~809-~809: In standard English, the word ‘exists’ is a verb. Please verify that the determiner ‘an’ is correct, or that a noun is not missing between ‘an’ and ‘exists’.
Context: ...## .putMeta(name, meta[, options]) Set an exists object meta. parameters: - name {Stri...(A_INFINITIVE)
[uncategorized] ~857-~857: The preposition ‘at’ seems more likely in this position.
Context: ...Object>} object names, max 1000 objects in once. - key {String} object name - ...(AI_HYDRA_LEO_REPLACE_IN_AT)
[uncategorized] ~863-~863: Possible missing comma found.
Context: ...lete succes, return emtpy response. otherwise return delete error object results. ...(AI_HYDRA_LEO_MISSING_COMMA)
[grammar] ~928-~928: The modal verb ‘will’ requires the verb’s base form.
Context: ...meta info list EachObjectMetawill contains blow properties: - name {String} obje...(MD_BASEFORM)
[uncategorized] ~947-~947: Possible missing preposition found.
Context: ...t total use time (ms) example: - List top 10 objects ```js const result = await ...(AI_HYDRA_LEO_MISSING_OF)
[grammar] ~993-~993: The modal verb ‘will’ requires the verb’s base form.
Context: ...meta info list EachObjectMetawill contains blow properties: - name {String} obje...(MD_BASEFORM)
[uncategorized] ~1013-~1013: Possible missing preposition found.
Context: ...er} request total use time (ms) - List top 10 objects ```js const result = await ...(AI_HYDRA_LEO_MISSING_OF)
[grammar] ~1072-~1072: The modal verb ‘will’ requires the verb’s base form.
Context: ...meta info list EachObjectMetawill contains blow properties: - name {String} obje...(MD_BASEFORM)
[grammar] ~1128-~1128: There is an agreement error between ‘put’ and ‘object’. Insert ‘a(n)’ or change the noun to plural.
Context: ...for download or upload object. When you put object with signatureUrl ,you need to pass `Co...(PRP_VB_NN)
[uncategorized] ~1151-~1151: The abbreviation “e.g.” (= for example) requires two periods.
Context: ...ject} set the custom value for callback,eg. {var1: value1,var2:value2} Success wil...(E_G)
[typographical] ~1208-~1208: Consider adding a comma after ‘Basically’ for more clarity.
Context: ...## .asyncSignatureUrl(name[, options]) Basically the same as signatureUrl, if refreshSTS...(RB_LY_COMMA)
[uncategorized] ~1232-~1232: The abbreviation “e.g.” (= for example) requires two periods.
Context: ...ject} set the custom value for callback,eg. {var1: value1,var2:value2} Success wil...(E_G)
[misspelling] ~1312-~1312: Use “a” instead of ‘an’ if the following word doesn’t start with a vowel sound, e.g. ‘a sentence’, ‘a university’.
Context: ...ssdemo.txt', 'public-read');- Set an history object's ACLjs const versi...(EN_A_VS_AN)
[misspelling] ~1350-~1350: Use “a” instead of ‘an’ if the following word doesn’t start with a vowel sound, e.g. ‘a sentence’, ‘a university’.
Context: ...'); console.log(result.acl);- Get an history object's ACLjs const versi...(EN_A_VS_AN)
[misspelling] ~1404-~1404: Use “a” instead of ‘an’ if the following word doesn’t start with a vowel sound, e.g. ‘a sentence’, ‘a university’.
Context: ...sole.log(result.status);- Restore an history objectjs const versionId =...(EN_A_VS_AN)
[uncategorized] ~1534-~1534: The abbreviation “e.g.” (= for example) requires two periods.
Context: ...ng} the object name - tag {Object} tag, eg.{var1: value1,var2:value2}- [options...(E_G)
[uncategorized] ~1552-~1552: The abbreviation “e.g.” (= for example) requires two periods.
Context: ...ng} the object name - tag {Object} tag, eg.{var1: value1,var2:value2}- [options...(E_G)
[grammar] ~1592-~1592: The modal verb ‘will’ requires the verb’s base form.
Context: ...s Each error return by OSS server will contains these properties: - name {String} erro...(MD_BASEFORM)
🪛 markdownlint-cli2 (0.17.2)
184-184: Bare URL used
null(MD034, no-bare-urls)
test/OSSObject.test.ts (1)
702-714: Use consistent Buffer utility methods.The implementation uses both
Buffer.byteLengthand string concatenation to determine content length.For better readability, consider:
- 'content-length': Buffer.byteLength( - 'Hello, 你好 OSS', - 'utf8' - ).toString(), + 'content-length': String(Buffer.byteLength('Hello, 你好 OSS', 'utf8')),src/OSSObject.ts (1)
1096-1098:successStatusestoo narrow for PUT/POST uploadsOSS may legitimately return
201(Created) for some PUT/POST operations (e.g. object upload withx-oss-forbid-overwrite). Limiting to[200]forces an unnecessary retry path.- params.successStatuses = [200]; + params.successStatuses = [200, 201];src/OSSBaseClient.ts (1)
190-194: Avoid double allocation when computing MD5
Buffer.from(params.content)allocates a new buffer althoughparams.contentis already aBuffer.- headers['content-md5'] = createHash('md5') - .update(Buffer.from(params.content)) + headers['content-md5'] = createHash('md5') + .update(params.content) .digest('base64');Reduces one copy per request and a few CPU cycles.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
.eslintrc(0 hunks).github/workflows/nodejs.yml(1 hunks).github/workflows/release.yml(1 hunks).husky/pre-commit(1 hunks).oxlintrc.json(1 hunks).prettierignore(1 hunks).prettierrc(1 hunks)README.md(42 hunks)package.json(2 hunks)src/OSSBaseClient.ts(11 hunks)src/OSSObject.ts(47 hunks)src/error/OSSClientError.ts(1 hunks)src/type/Object.ts(2 hunks)src/type/Request.ts(1 hunks)src/util/checkBucketName.ts(1 hunks)src/util/checkObjectTag.ts(1 hunks)src/util/encodeCallback.ts(2 hunks)src/util/json2xml.ts(2 hunks)src/util/policyToJSONString.ts(1 hunks)src/util/sign.ts(5 hunks)test/OSSObject.test.ts(81 hunks)test/config.ts(1 hunks)test/util/isIP.test.ts(1 hunks)
💤 Files with no reviewable changes (1)
- .eslintrc
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/util/sign.ts (3)
src/type/Request.ts (2)
RequestParameters(5-8)Request(18-21)src/OSSObject.ts (2)
method(1140-1155)options(1118-1135)src/OSSBaseClient.ts (4)
request(234-263)signature(71-74)authorization(91-109)options(267-292)
src/OSSBaseClient.ts (3)
src/type/Request.ts (3)
RequestParameters(5-8)OSSRequestParams(23-44)OSSResult(46-49)src/util/sign.ts (2)
buildCanonicalString(65-94)authorization(104-111)src/error/OSSClientError.ts (1)
OSSClientError(5-28)
🪛 LanguageTool
README.md
[uncategorized] ~863-~863: Possible missing comma found.
Context: ...lete succes, return emtpy response. otherwise return delete error object results. ...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 Biome (1.9.4)
.oxlintrc.json
[error] 26-26: Expected a property but instead found '// eslint'.
Expected a property here.
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 28-28: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 28-28: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 28-28: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 28-28: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 29-29: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 29-29: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 29-29: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 29-29: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 30-30: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 30-30: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 30-30: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 30-30: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 32-32: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 32-32: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 32-32: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 32-32: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 33-33: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 33-33: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 33-33: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 33-33: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 34-34: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 34-34: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 34-34: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 34-34: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 35-35: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 35-35: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 35-35: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 35-35: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 36-36: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 36-36: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 36-36: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 36-36: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 37-37: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 37-37: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 37-37: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 37-37: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 38-38: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 38-38: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 38-38: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 38-38: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 39-39: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 39-39: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 39-39: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 39-39: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 40-40: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 40-40: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 40-40: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 40-40: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 41-41: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 41-41: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 41-41: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 41-41: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 42-42: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 42-42: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 42-42: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 42-42: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 43-43: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 43-43: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 43-43: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 43-43: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 44-44: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 44-44: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 44-44: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 44-44: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 45-45: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 45-45: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 45-45: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 45-45: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 46-46: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 46-46: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 46-46: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 46-46: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 47-47: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 47-47: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 47-47: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 47-47: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 48-48: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 48-48: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 48-48: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 48-48: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 49-49: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 49-49: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 49-49: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 49-49: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 50-50: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 50-50: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 50-50: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 50-50: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 51-51: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 51-51: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 51-51: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 51-51: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 52-52: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 52-52: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 52-52: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 52-52: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 53-53: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 53-53: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 53-53: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 53-54: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 55-55: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 55-55: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 55-55: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 55-55: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 56-56: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 56-56: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 56-56: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 56-56: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 57-57: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 57-57: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 57-57: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 57-57: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 58-58: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 58-58: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 58-58: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 58-58: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 59-59: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 59-59: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 59-59: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 59-59: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 60-60: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 60-60: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 60-60: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 60-60: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 61-61: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 61-61: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 61-61: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 61-61: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 62-62: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 62-62: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 62-62: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 62-62: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 63-63: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 63-63: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 63-63: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 63-63: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 64-64: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 64-64: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 64-64: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 64-64: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 65-65: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 65-65: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 65-65: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 65-65: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 66-66: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 66-66: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 66-66: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 66-66: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 67-67: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 67-67: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 67-67: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 67-67: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 68-68: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 68-68: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 68-68: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 68-70: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 71-71: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 71-71: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 71-71: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 71-71: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 72-72: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 72-72: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 72-72: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 72-72: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 73-73: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 73-73: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 73-73: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 73-73: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 74-74: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 74-74: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 74-74: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 74-74: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 75-75: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 75-75: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 75-75: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 75-75: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 76-76: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 76-76: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 76-76: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 76-76: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 77-77: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 77-77: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 77-77: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 77-77: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 78-78: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 78-78: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 78-78: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 78-78: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 79-79: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 79-79: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 79-79: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 79-79: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 80-80: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 80-80: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 80-80: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 80-82: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 83-83: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 83-83: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 83-83: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 83-83: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 84-84: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 84-84: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 84-84: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 84-84: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 85-85: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 85-85: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 85-85: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 85-85: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 86-86: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 86-86: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 86-86: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 86-86: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 87-87: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 87-87: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 87-87: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 87-87: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 88-88: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 88-88: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 88-88: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 88-88: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 89-89: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 89-89: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 89-89: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 89-91: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 92-92: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 92-92: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 92-92: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 92-92: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 93-93: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 93-93: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 93-93: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 93-93: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 94-94: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 94-94: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 94-94: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 94-94: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 95-95: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 95-95: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 95-95: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 95-95: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 96-96: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 96-96: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 96-96: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 96-96: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 97-97: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 97-97: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 97-97: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 97-97: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 98-98: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 98-98: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 98-98: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 98-98: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 99-99: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 99-99: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 99-99: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 99-100: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 101-101: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 101-101: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 101-101: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 101-101: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 102-102: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 102-102: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 102-102: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 102-102: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 103-103: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 103-103: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 103-103: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 103-103: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 104-104: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 104-104: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 104-104: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 104-104: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 105-105: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 105-105: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 105-105: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 105-105: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 106-106: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 106-106: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 106-106: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 106-106: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 107-107: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 107-107: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 107-107: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 107-107: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 108-108: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 108-108: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 108-108: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 108-108: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 109-109: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 109-109: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 109-109: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 109-109: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 110-110: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 110-110: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 110-110: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 110-110: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 111-111: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 111-111: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 111-111: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 111-111: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 112-112: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 112-112: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 112-112: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 112-112: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 113-113: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 113-113: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 113-113: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 113-113: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 114-114: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 114-114: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 114-114: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 114-114: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 115-115: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 115-115: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 115-115: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 115-117: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 118-118: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 118-118: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 118-118: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 118-118: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 119-119: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 119-119: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 119-119: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 119-119: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 120-120: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 120-120: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 120-120: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 120-120: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 121-121: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 121-121: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 121-121: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 121-123: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 124-124: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 124-124: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 124-124: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 124-124: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 125-125: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 125-125: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 125-125: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 125-125: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 126-126: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 126-126: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 126-126: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 126-126: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 127-127: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 127-127: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 127-127: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 127-127: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 128-128: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 128-128: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 128-128: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 128-128: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 129-129: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 129-129: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 129-129: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 129-129: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 130-130: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 130-130: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 130-130: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 130-130: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 131-131: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 131-131: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 131-131: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 131-131: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 132-132: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 132-132: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 132-132: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 132-132: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 133-133: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 133-133: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 133-133: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 133-133: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 134-134: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 134-134: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 134-134: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 134-134: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 135-135: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 135-135: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 135-135: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 135-135: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 136-136: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 136-136: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 136-136: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 136-138: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 139-139: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 139-139: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 139-139: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 139-139: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 140-140: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 140-140: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 140-140: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 141-141: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 142-142: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 142-142: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 142-142: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 142-143: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
🪛 GitHub Check: build (24, ubuntu-latest)
src/OSSBaseClient.ts
[failure] 238-238: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store object to writeStream
Error: Cannot pipe to a closed or destroyed stream
❯ HttpClient.#requestInternal node_modules/urllib/src/HttpClient.ts:643:17
❯ HttpClient.request node_modules/urllib/src/HttpClient.ts:246:12
❯ OSSObject.request src/OSSBaseClient.ts:238:20
❯ OSSObject.get src/OSSObject.ts:383:16
❯ test/OSSObject.test.ts:1589:22
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_STREAM_UNABLE_TO_PIPE', opaque: undefined, status: 200, headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:25 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3D0482F43637297E41', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '14' }, res: { status: 200, statusCode: 200, statusText: 'OK', statusMessage: 'OK', headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:25 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3D0482F43637297E41', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '14' }, size: 90839, aborted: false, rt: 1072.76, keepAliveSocket: true, requestUrls: [ 'https://..aliyuncs.com/linux-v24.0.0-1746852855756/oss-client/oss/get-meta.js' ], timing: { queuing: 0.095, dnslookup: +0, connected: 836.136, requestHeadersSent: 836.214, requestSent: 836.284, waiting: 1072.471, contentDownload: +0 }, socket: { id: 5, localAddress: '10.1.0.5', localPort: 52860, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 365, bytesRead: 4096, handledRequests: 1, handledResponses: 1, connectedTime: '2025-05-10T04:55:25.136Z' }, retries: +0, socketErrorRetries: +0 }, socket: { id: 5, localAddress: '10.1.0.5', localPort: 52860, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 365, bytesRead: 4096, handledRequests: 1, handledResponses: 1, connectedTime: '2025-05-10T04:55:25.136Z' } }
[failure] 238-238: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should escape uri path ok
Error: Cannot pipe to a closed or destroyed stream
❯ HttpClient.#requestInternal node_modules/urllib/src/HttpClient.ts:643:17
❯ HttpClient.request node_modules/urllib/src/HttpClient.ts:246:12
❯ OSSObject.request src/OSSBaseClient.ts:238:20
❯ OSSObject.get src/OSSObject.ts:383:16
❯ test/OSSObject.test.ts:1563:22
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_STREAM_UNABLE_TO_PIPE', opaque: undefined, status: 200, headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:24 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3C2E2F78353286872E', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '12' }, res: { status: 200, statusCode: 200, statusText: 'OK', statusMessage: 'OK', headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:24 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3C2E2F78353286872E', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '12' }, size: 90839, aborted: false, rt: 231.396, keepAliveSocket: true, requestUrls: [ 'https://..aliyuncs.com/linux-v24.0.0-1746852855756/oss-client/oss/%253get%2Bmeta.js' ], timing: { queuing: 0.088, dnslookup: +0, connected: +0, requestHeadersSent: 0.127, requestSent: 0.182, waiting: 230.966, contentDownload: +0 }, socket: { id: 1, localAddress: '10.1.0.5', localPort: 34320, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 9637827, bytesRead: 1923049, handledRequests: 117, handledResponses: 117, connectedTime: '2025-05-10T04:54:17.257Z', lastRequestEndTime: '2025-05-10T04:55:23.799Z' }, retries: +0, socketErrorRetries: +0 }, socket: { id: 1, localAddress: '10.1.0.5', localPort: 34320, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 9637827, bytesRead: 1923049, handledRequests: 117, handledResponses: 117, connectedTime: '2025-05-10T04:54:17.257Z', lastRequestEndTime: '2025-05-10T04:55:23.799Z' } }
[failure] 238-238: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store object to local file
Error: Cannot pipe to a closed or destroyed stream
❯ HttpClient.#requestInternal node_modules/urllib/src/HttpClient.ts:643:17
❯ HttpClient.request node_modules/urllib/src/HttpClient.ts:246:12
❯ OSSObject.request src/OSSBaseClient.ts:238:20
❯ OSSObject.get src/OSSObject.ts:383:16
❯ test/OSSObject.test.ts:1546:22
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_STREAM_UNABLE_TO_PIPE', opaque: undefined, status: 200, headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:23 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3B0EF7D03538BA4A7A', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '12' }, res: { status: 200, statusCode: 200, statusText: 'OK', statusMessage: 'OK', headers: { server: 'AliyunOSS', date: 'Sat, 10 May 2025 04:55:23 GMT', 'content-type': 'video/mp2t', 'content-length': '90839', connection: 'keep-alive', 'x-oss-request-id': '681EDC3B0EF7D03538BA4A7A', 'accept-ranges': 'bytes', etag: '"64ADE9929664E066DBC0D45974A6E2A6"', 'last-modified': 'Sat, 10 May 2025 04:55:23 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crc64ecma': '8275475219421965874', 'x-oss-storage-class': 'IA', 'x-oss-meta-pid': '123', 'x-oss-meta-slus': 'test.html', 'x-oss-meta-uid': '1', 'content-md5': 'ZK3pkpZk4GbbwNRZdKbipg==', 'x-oss-server-time': '12' }, size: 90839, aborted: false, rt: 257.566, keepAliveSocket: true, requestUrls: [ 'https://..aliyuncs.com/linux-v24.0.0-1746852855756/oss-client/oss/get-meta.js' ], timing: { queuing: 0.064, dnslookup: +0, connected: +0, requestHeadersSent: 0.097, requestSent: 0.159, waiting: 257.21, contentDownload: +0 }, socket: { id: 3, localAddress: '10.1.0.5', localPort: 41758, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 12862, bytesRead: 1360201, handledRequests: 29, handledResponses: 29, connectedTime: '2025-05-10T04:54:57.661Z', lastRequestEndTime: '2025-05-10T04:55:23.018Z' }, retries: +0, socketErrorRetries: +0 }, socket: { id: 3, localAddress: '10.1.0.5', localPort: 41758, remoteAddress: '47.101.28.51', remotePort: 443, remoteFamily: 'IPv4', bytesWritten: 12862, bytesRead: 1360201, handledRequests: 29, handledResponses: 29, connectedTime: '2025-05-10T04:54:57.661Z', lastRequestEndTime: '2025-05-10T04:55:23.018Z' } }
test/OSSObject.test.ts
[failure] 1603-1603: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store not exists object to file
AssertionError: Expected values to be strictly equal:
-
actual - expected
-
'ERR_STREAM_UNABLE_TO_PIPE'
- 'NoSuchKey'
Expected: "NoSuchKey"
Received: "ERR_STREAM_UNABLE_TO_PIPE"
❯ Object. test/OSSObject.test.ts:1603:18
❯ test/OSSObject.test.ts:1598:7
🪛 GitHub Check: build (20, ubuntu-latest)
test/OSSObject.test.ts
[failure] 1603-1603: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store not exists object to file
AssertionError: Expected values to be strictly equal:
-
actual - expected
-
'ENOENT'
- 'NoSuchKey'
Expected: "NoSuchKey"
Received: "ENOENT"
❯ Object. test/OSSObject.test.ts:1603:18
❯ test/OSSObject.test.ts:1598:7
🪛 GitHub Check: build (18, ubuntu-latest)
test/OSSObject.test.ts
[failure] 1603-1603: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store not exists object to file
AssertionError: Expected values to be strictly equal:
-
actual - expected
-
'ENOENT'
- 'NoSuchKey'
Expected: "NoSuchKey"
Received: "ENOENT"
❯ Object. test/OSSObject.test.ts:1603:18
❯ test/OSSObject.test.ts:1598:7
🪛 GitHub Check: build (22, ubuntu-latest)
test/OSSObject.test.ts
[failure] 1603-1603: test/OSSObject.test.ts > test/OSSObject.test.ts > get() > should store not exists object to file
AssertionError: Expected values to be strictly equal:
-
actual - expected
-
'ENOENT'
- 'NoSuchKey'
Expected: "NoSuchKey"
Received: "ENOENT"
❯ Object. test/OSSObject.test.ts:1603:18
❯ test/OSSObject.test.ts:1598:7
🪛 GitHub Actions: Node.js CI
test/OSSObject.test.ts
[error] 1486-1486: Test timed out in 5000ms for 'should signature url with traffic limit'. Consider increasing timeout with 'testTimeout' option.
[error] 1546-1546: Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should store object to local file'.
[error] 1563-1563: Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should escape uri path ok'.
[error] 1589-1589: Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should store object to writeStream'.
[error] 1603-1603: AssertionError: Expected error code 'NoSuchKey' but received 'ERR_STREAM_UNABLE_TO_PIPE' in 'should store not exists object to file'.
🔇 Additional comments (30)
test/util/isIP.test.ts (1)
3-3: Tests updated for Vitest.
Importingdescribeanditfrom Vitest aligns the tests with the new testing framework..github/workflows/nodejs.yml (2)
21-21: Update tested Node.js versions.
Testing against Node.js v18, v20, v22, and the newly released v24 ensures CI compatibility with supported and current versions.
45-46: Bump Codecov action to v5.
Upgradingcodecov/codecov-actionfrom v3 to v5 aligns with the latest version of the action and its features..github/workflows/release.yml (1)
5-5: Standardize branch syntax.
The formatting change tobranches: [master]improves consistency without affecting workflow behavior.src/util/checkBucketName.ts (1)
2-4: Reformat ternary assignment.
Splitting thebucketRegexassignment into a multiline conditional enhances readability while preserving existing logic.src/util/encodeCallback.ts (1)
20-22: Reformat base64 encoding calls.
Splitting the.toString('base64')invocation across lines improves formatting in accordance with Prettier’s style rules.Also applies to: 32-34
src/type/Object.ts (2)
2-7: Clean import formatting looks good!The multi-line import style improves readability when importing multiple types.
170-171: Interface extension formatting looks good!The multi-line interface extension syntax is more readable and consistent with the formatting style being applied throughout the codebase.
src/type/Request.ts (2)
5-8: Union type formatting looks good!The multi-line format for the
RequestParametersunion type improves readability.
10-16: HTTP method union type formatting looks good!The multi-line format for the
RequestMethodunion type makes each HTTP method clearly visible, improving readability.src/error/OSSClientError.ts (1)
12-21: Constructor formatting looks good!The multi-line formatting for both the constructor parameters and the super call improves readability, especially with the template string construction in the error message.
src/util/policyToJSONString.ts (1)
6-8: Great improvement to error handling!The updated error handling is more type-safe by checking if the caught error is an instance of Error before accessing the message property. Using
String(err)as a fallback ensures that the error message is always a string, making the code more robust against different error types.src/util/checkObjectTag.ts (2)
11-22: Preserved validation logic with improved readability
The multi-line condition clearly checks that keys always match the allowed pattern and values only if non-empty. No change in runtime behavior.
23-27: Explicit length check improves clarity
Switching fromkey.length < 1tokey.length === 0makes the lower-bound check more explicit without altering logic.src/util/json2xml.ts (2)
3-6: Enhanced type safety in function signature
UpdatingjsontoRecord<string, unknown>and formatting the parameters across multiple lines boosts readability and type correctness.
21-23: Safe cast for recursive calls
You guard againstnull/undefinedbefore casting toRecord<string, unknown>, maintaining runtime safety while satisfying TypeScript..prettierignore (1)
1-3: Prettier ignore patterns look good
ExcludingCHANGELOG.mdand__snapshots__prevents formatting of non-code files and snapshots..prettierrc (1)
1-6: New Prettier configuration looks good.The Prettier configuration includes sensible defaults that align with modern JavaScript/TypeScript practices:
- Single quotes for string literals
- ES5-compatible trailing commas
- 2-space indentation
- Omitting parentheses around single arrow function parameters
This configuration complements the migration from ESLint to Prettier for code formatting as mentioned in the PR objectives.
test/config.ts (3)
1-1: Good addition of typed environment variable handling.Using the
read-env-valuepackage provides better type safety and explicit default values compared to directly accessingprocess.env.
4-4: Nice simplification using Date.now().Replacing
new Date().getTime()with the equivalent but more conciseDate.now()improves code readability.
6-14: Good addition of explicit type handling and default values.The use of the
envfunction with explicit types and default values for OSS configuration enhances robustness by:
- Ensuring type safety through explicit type declarations
- Providing fallback values for when environment variables are not set
- Making the configuration more maintainable and self-documenting
This approach is more resilient than directly accessing
process.env.test/OSSObject.test.ts (5)
3-8: Good practice: Organized imports for better readability.The reworked import statements clearly separate core Node.js modules from third-party dependencies, making the dependencies more obvious at a glance.
15-28: Migration to Vitest testing framework.Correctly updated imports to use Vitest testing functions instead of Mocha. This change is consistent with the toolchain migration mentioned in the PR objectives.
38-39: Good practice: Using assert.ok for boolean checks.Replacing direct assert calls with
assert.okfor boolean checks is more explicit about the intention of the assertion, improving code readability.Also applies to: 78-84, 91-93, 137-140, 179-180, 316-317, 327-328, 341-342, 356-357, 368-369
50-71: Updated lifecycle hooks from Mocha to Vitest.Correctly migrated from Mocha's
before/afterto Vitest'sbeforeAll/afterAllhooks, which is necessary for compatibility with the new testing framework.Also applies to: 230-251
501-513: Improved assertion callback formatting.The refactored
assert.rejectsblocks are more readable with properly indented callback functions, making the error-handling tests easier to follow.Also applies to: 615-633, 659-670, 680-688, 851-866, 872-880, 1010-1018, 1051-1062, 1199-1210, 1252-1266, 1598-1608, 1672-1682, 1730-1749, 1792-1805, 2152-2161, 2287-2303
package.json (3)
9-16: Well-structured NPM scripts for the new toolchain.The scripts have been appropriately updated to use the new tools:
lintnow usesoxlintinstead of ESLint- Added
pretestto run linting with auto-fix before tests- Modified
testandcovcommands to use Vitest instead of egg-bin- Added
preparescript for Husky Git hooks integrationThese changes align perfectly with the PR objective of migrating to Prettier, OXLint, and Vitest.
18-23: Good configuration for lint-staged.The lint-staged configuration ensures that:
- All files are formatted with Prettier
- TypeScript, JavaScript, JSON, Markdown, and YAML files are also checked and fixed with OXLint
This setup enforces code quality standards at commit time, which is a best practice for maintaining consistent code style across the project.
57-67: Appropriate dependency updates for the new toolchain.The updated dependencies reflect the migration from ESLint and egg-bin to OXLint, Prettier, and Vitest:
- Added
@vitest/coverage-v8for test coverage reporting- Added
huskyfor Git hooks management- Added
oxlintfor linting- Added
prettierfor code formatting- Added
read-env-valuefor type-safe environment variable handling- Updated TypeScript to a newer version
- Added
vitestas the testing frameworkThese changes are consistent with the PR objectives and ensure the project uses modern tooling.
.oxlintrc.json (1)
26-34:Details
❓ Verification inconclusive
File is not valid JSON – comments trigger JSON parser errors
The file extension is
.json, but inline//comments violate the JSON spec and are flagged by Biome. Unlessoxlintexplicitly supports “JSONC”, this will prevent the linter from loading.Options:
- Rename to
.oxlintrc.jsonc/.oxlintrc.json5(if supported by oxlint).- Keep the name but switch to pure JSON – move comments to project docs instead.
Failing to load this config will silently disable the very rules we expect.
Invalid JSON in .oxlintrc.json (comments will break parsing)
The
.oxlintrc.jsonfile currently includes//comments (e.g. lines 26–34), which are not valid in standard JSON. If OXLint (via Biome) doesn’t support JSONC/JSON5, the config will fail to load and may silently disable your lint rules.Suggestions:
- Rename the file to
.oxlintrc.jsoncor.oxlintrc.json5if your version of OXLint/Biome supports JSONC/JSON5 syntax.- Otherwise, remove all inline comments and move them into project documentation so the file remains pure JSON.
Please verify whether your OXLint/Biome version supports JSONC before renaming or stripping comments.
🧰 Tools
🪛 Biome (1.9.4)
[error] 26-26: Expected a property but instead found '// eslint'.
Expected a property here.
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 28-28: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 28-28: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 28-28: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 28-28: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 29-29: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 29-29: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 29-29: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 29-29: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 30-30: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 30-30: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 30-30: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 30-30: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 32-32: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 32-32: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 32-32: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 32-32: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 33-33: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 33-33: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 33-33: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 33-33: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 34-34: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 34-34: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 34-34: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 34-34: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
| ); | ||
| const { size } = await stat(__filename); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix test failures in file operations.
The pipeline is showing failures in tests involving file streams and error handling:
Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should store object to local file'.
Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should escape uri path ok'.
Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should store object to writeStream'.
AssertionError: Expected error code 'NoSuchKey' but received 'ERR_STREAM_UNABLE_TO_PIPE' in 'should store not exists object to file'.
These errors suggest issues with stream handling that need to be addressed when migrating to the new testing framework.
Consider updating the implementation to properly handle stream errors and cleanup, ensuring streams are properly closed when errors occur:
- await assert.rejects(
- async () => {
- await ossObject.get(`${name}not-exists`, savePath);
- },
- (err: OSSClientError) => {
- assert.equal(err.code, 'NoSuchKey');
- assert.equal(err.status, 404);
- assert.ok(!existsSync(savePath));
- return true;
- }
- );
+ await assert.rejects(
+ async () => {
+ try {
+ await ossObject.get(`${name}not-exists`, savePath);
+ } catch (err) {
+ // Ensure any created streams are properly closed
+ throw err;
+ }
+ },
+ (err: OSSClientError | Error) => {
+ // Handle both OSSClientError and stream errors
+ if ('code' in err) {
+ assert.equal(err.code, 'NoSuchKey');
+ assert.equal((err as OSSClientError).status, 404);
+ }
+ assert.ok(!existsSync(savePath));
+ return true;
+ }
+ );Also applies to: 1559-1562, 1588-1594, 1597-1609
🧰 Tools
🪛 GitHub Actions: Node.js CI
[error] 1546-1546: Error 'Cannot pipe to a closed or destroyed stream' occurred in 'should store object to local file'.
| (headers['content-md5'] as string) ?? '', | ||
| headers['content-type'] as string, | ||
| expiresTimestamp || (headers['x-oss-date'] as string), | ||
| ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
content-type may be undefined – pushes literal 'undefined' into the string-to-sign
If the caller omits a Content-Type header the expression
headers['content-type'] as stringinserts the string “undefined”, changing the canonical string and producing an invalid signature.
Use an empty string fallback, mirroring content-md5 handling:
- (headers['content-type'] as string,
+ (headers['content-type'] as string) ?? '',
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #27 +/- ##
==========================================
- Coverage 94.39% 91.40% -2.99%
==========================================
Files 17 15 -2
Lines 1891 1443 -448
Branches 282 291 +9
==========================================
- Hits 1785 1319 -466
- Misses 106 124 +18 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
[skip ci] ## [2.5.0](v2.4.0...v2.5.0) (2025-05-10) ### Features * use prettier, oxlint and vitest ([#27](#27)) ([d411a9f](d411a9f))
Summary by CodeRabbit
New Features
Chores
Documentation
Refactor & Style
Tests