-
Notifications
You must be signed in to change notification settings - Fork 41
feat: Command Line SDK update for version 13.0.0-rc.1 #223
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 pull request represents a major codebase migration from JavaScript to TypeScript for the Appwrite CLI. The version is bumped from 12.0.1 to 13.0.0-rc.1. Key infrastructure files are rewritten with ES module syntax and type safety: index.js (bootstrap) → index.ts, lib/client.js → lib/client.ts, lib/config.js → lib/config.ts, lib/exception.js → lib/exception.ts, lib/parser.js → lib/parser.ts, lib/sdks.js → lib/sdks.ts, and lib/emulation/utils.js → lib/emulation/utils.ts. Over 60 command modules are migrated from CommonJS to TypeScript with explicit parameter interfaces and named exports. Installation scripts and documentation are updated to reflect the new version. Core patterns include converting require to import, module.exports to named exports, and introducing TypeScript interfaces for all public function parameters. Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes This is a comprehensive, large-scale refactoring affecting core infrastructure and the majority of the codebase. While the migration pattern is relatively consistent, the sheer volume of files (100+), the complete rewrite of critical modules, and the density of logic changes across CLI commands, error handling, SDK factories, and configuration management demand thorough review.
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
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 updates the Command Line SDK to version 13.0.0-rc.1 by migrating JavaScript files to TypeScript across multiple library modules. The changes involve converting CommonJS modules to ES modules, adding type annotations, and removing unnecessary files.
Key changes:
- Migrated core library files from JavaScript (.js) to TypeScript (.ts) with proper type definitions
- Converted module.exports to ES module exports across all files
- Added comprehensive TypeScript interfaces for function parameters and return types
Reviewed changes
Copilot reviewed 57 out of 76 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/type-generation/languages/javascript.js | Deleted JavaScript implementation |
| lib/type-generation/languages/java.ts | Migrated to TypeScript with type annotations |
| lib/type-generation/languages/dart.ts | Migrated to TypeScript with type annotations |
| lib/type-generation/languages/csharp.ts | Migrated to TypeScript with type annotations |
| lib/type-generation/attribute.ts | New TypeScript attribute type definitions |
| lib/type-generation/attribute.js | Deleted JavaScript implementation |
| lib/spinner.ts | Migrated to TypeScript with interfaces and type safety |
| lib/sdks.ts | Migrated to TypeScript with proper return types |
| lib/sdks.js | Deleted JavaScript implementation |
| lib/questions.ts | Migrated to TypeScript with comprehensive interfaces |
| lib/parser.ts | Migrated to TypeScript with type-safe exports |
| lib/parser.js | Deleted JavaScript implementation |
| lib/paginate.ts | Migrated to TypeScript with generic types |
| lib/id.ts | Migrated to TypeScript with method signatures |
| lib/exception.ts | New TypeScript exception class |
| lib/exception.js | Deleted JavaScript implementation |
| lib/emulation/utils.ts | Migrated to TypeScript with interfaces |
| lib/emulation/utils.js | Deleted JavaScript implementation |
| lib/emulation/docker.ts | Migrated to TypeScript with function signatures |
| lib/config.ts | Migrated to TypeScript with extensive type definitions |
| lib/config.js | Deleted JavaScript implementation |
| lib/commands/vcs.ts | Migrated to TypeScript with interface definitions |
| lib/commands/users.ts | Migrated to TypeScript with interface definitions |
| lib/commands/update.ts | Migrated to TypeScript with type safety |
| lib/commands/types.ts | Migrated to TypeScript with type annotations |
| lib/commands/tokens.ts | Migrated to TypeScript with interface definitions |
| lib/commands/teams.ts | Migrated to TypeScript with interface definitions |
| lib/commands/storage.ts | Migrated to TypeScript with interface definitions |
| lib/commands/run.ts | Migrated to TypeScript with interface definitions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (13)
lib/emulation/docker.ts (1)
21-31: Docker process promises don't check exit codes.The
dockerStop,dockerPull,dockerBuild, and copy process all resolve oncloseevent without checking if the process succeeded. A non-zero exit code would still resolve the promise, potentially masking failures.🔎 Proposed fix for dockerStop
export async function dockerStop(id: string): Promise<void> { const stopProcess = childProcess.spawn('docker', ['rm', '--force', id], { stdio: 'pipe', env: { ...process.env, DOCKER_CLI_HINTS: 'false' } }); - await new Promise<void>((res) => { stopProcess.on('close', res) }); + await new Promise<void>((resolve, reject) => { + stopProcess.on('close', (code) => { + if (code === 0 || code === null) { + resolve(); + } else { + reject(new Error(`docker rm failed with exit code ${code}`)); + } + }); + stopProcess.on('error', reject); + }); }Apply similar pattern to
dockerPulland the copy process indockerBuild.Also applies to: 49-50, 128-128, 150-150
lib/commands/update.ts (1)
178-187: Version comparison logic is inverted.The condition
comparison < 0with message "You're running a newer version" is backwards. Whencomparison < 0, it means the current version is older than the latest version, not newer. Change the condition tocomparison > 0or swap the logic between these two branches.lib/commands/types.ts (1)
73-83: Type assertion after auto-detection can cause runtime failures.The
detectLanguage()function (lib/type-generation/languages/language.ts line 83-119) can return 'python', 'ruby', or 'dotnet', butSupportedLanguage(lib/commands/types.ts line 17) is defined as'ts' | 'js' | 'php' | 'kotlin' | 'swift' | 'java' | 'dart' | 'cs'. The type assertionas SupportedLanguageon line 83 suppresses this incompatibility. If auto-detection returns an unsupported language,createLanguageMeta()will throw a runtime error instead of failing at compile time.lib/spinner.ts (1)
96-104: Off-by-one error in spinner frame iteration.The spinner animation skips the first frame (index 0) because
spinnerFramestarts at 1 and is incremented before use. Also, the fallback key'dots'should use the constantSPINNER_DOTSfor consistency.🔎 Proposed fix
startSpinner(name: string): void { - let spinnerFrame = 1; - const spinner = spinners[name] ?? spinners['dots']; + let spinnerFrame = 0; + const spinner = spinners[name] ?? spinners[SPINNER_DOTS]; this.spinnerInterval = setInterval(() => { - if (spinnerFrame === spinner.frames.length) spinnerFrame = 1; - this.bar.update({ prefix: spinner.frames[spinnerFrame++] }); + this.bar.update({ prefix: spinner.frames[spinnerFrame] }); + spinnerFrame = (spinnerFrame + 1) % spinner.frames.length; }, spinner.interval); }lib/commands/run.ts (1)
192-216: Inconsistentignoremodule usage.Line 193 uses
ignore()directly while line 259 usesignore.default(). This inconsistency may cause issues depending on how the module is resolved. Both usages should be consistent.🔎 Proposed fix - use consistent initialization
if(reload) { - const ignorer = ignore(); + const ignorer = ignore.default(); ignorer.add('.appwrite');lib/commands/teams.ts (1)
469-498: Type mismatch:prefsis typed asobjectbut used withJSON.parse.The interface declares
prefs: objectbut line 483 callsJSON.parse(prefs), which expects a string. The CLI option on line 606 passes a string from the command line, so the interface type should bestringto match runtime usage.🔎 Proposed fix
interface TeamsUpdatePrefsRequestParams { teamId: string; - prefs: object; + prefs: string; overrideForCli?: boolean; parseOutput?: boolean; sdk?: Client; }lib/commands/users.ts (1)
1032-1060: Fixprefstyping vsJSON.parseinusersUpdatePrefs
UsersUpdatePrefsRequestParams.prefsis typed asobject, but the implementation assumes a JSON string and callsJSON.parse(prefs). This works for the CLI (which passes a string) but will throw for programmatic callers that follow the type and pass an object.I’d align the type with the behavior or handle both forms, e.g.:
Proposed fix: accept string or object
-interface UsersUpdatePrefsRequestParams { - userId: string; - prefs: object; +interface UsersUpdatePrefsRequestParams { + userId: string; + prefs: string | Record<string, unknown>; @@ -export const usersUpdatePrefs = async ({userId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePrefsRequestParams): Promise<any> => { +export const usersUpdatePrefs = async ({userId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePrefsRequestParams): Promise<any> => { @@ - if (typeof prefs !== 'undefined') { - payload['prefs'] = JSON.parse(prefs); - } + if (typeof prefs !== 'undefined') { + payload['prefs'] = + typeof prefs === 'string' ? JSON.parse(prefs) : prefs; + }lib/commands/functions.ts (3)
655-677: Off‑by‑one when trimming the last chunk inuploadChunkIn the non‑full‑chunk branch you allocate
new Uint8Array(currentPosition)but copy withi <= currentPosition, which writescurrentPosition + 1bytes and includes one extra (stale or zero) byte:uploadableChunkTrimmed = new Uint8Array(currentPosition); for (let i = 0; i <= currentPosition; i++) { uploadableChunkTrimmed[i] = uploadableChunk[i]; }This can desync the actual payload size from the declared content‑range and corrupt the last chunk.
Trim to exactly
currentPositionbytes:Proposed fix
- } else { - uploadableChunkTrimmed = new Uint8Array(currentPosition); - for(let i = 0; i <= currentPosition; i++) { - uploadableChunkTrimmed[i] = uploadableChunk[i]; - } - } + } else { + uploadableChunkTrimmed = new Uint8Array(currentPosition); + for (let i = 0; i < currentPosition; i++) { + uploadableChunkTrimmed[i] = uploadableChunk[i]; + } + }
1021-1053: Alignheaderstype withJSON.parseusage infunctionsCreateExecution
FunctionsCreateExecutionRequestParams.headersis typed asobject, but the code assumes a JSON string:if (typeof headers !== 'undefined') { payload['headers'] = JSON.parse(headers); }CLI passes a string, but the exported type invites callers to pass an object, which would cause
JSON.parseto throw.Consider mirroring the
prefsfix from users and accepting both string and object:Proposed fix
-interface FunctionsCreateExecutionRequestParams { +interface FunctionsCreateExecutionRequestParams { @@ - headers?: object; + headers?: string | Record<string, unknown>; @@ - if (typeof headers !== 'undefined') { - payload['headers'] = JSON.parse(headers); - } + if (typeof headers !== 'undefined') { + payload['headers'] = + typeof headers === 'string' ? JSON.parse(headers) : headers; + }
721-721: Usefs.promises.unlink()instead of callback-basedfs.unlink()Callback-based functions are incompatible with promises & async/await. The current code
await fs.unlink(filePath, () => {});does not actually wait for deletion since fs.unlink() is asynchronous by default and returns immediately without waiting for the file deletion to complete. Additionally, errors in the empty callback are silently discarded.Replace with:
- await fs.unlink(filePath,()=>{}); + await fs.promises.unlink(filePath);lib/commands/init.ts (1)
158-168: Bug: Usinganswers.bucketfor team name.Line 163 uses
answers.bucketbut this is theinitTeamfunction. This appears to be a copy-paste error frominitBucket. The team name should likely come fromanswers.nameor a team-specific answer field.🔎 Proposed fix
localConfig.addTeam({ $id: answers.id === 'unique()' ? ID.unique() : answers.id, - name: answers.bucket, + name: answers.name, });lib/commands/sites.ts (1)
720-720: Silent error handling infs.unlinkmay leave orphaned temp files.The
fs.unlinkcall uses an empty callback()=>{}, which silently ignores any errors. If the unlink fails (e.g., permission issues), the temporary archive file will remain on disk without any indication to the user.🔎 Proposed fix - add error logging
- await fs.unlink(filePath,()=>{}); + fs.unlink(filePath, (err) => { + if (err) { + warn(`Failed to clean up temporary file: ${filePath}`); + } + });lib/commands/account.ts (1)
671-685: Fix type mismatch forprefsparameter.Line 672 declares
prefs: object, but line 684 callsJSON.parse(prefs), which expects a string. Based on the CLI option at line 1681, the parameter should be typed asstringsince it's received as a JSON string from the command line.🔎 Proposed fix
interface AccountUpdatePrefsRequestParams { - prefs: object; + prefs: string; overrideForCli?: boolean; parseOutput?: boolean; sdk?: Client;
♻️ Duplicate comments (1)
lib/commands/project.ts (1)
1-13: Same unused imports pattern as other command files.This file contains the same boilerplate imports and unused
convertReadStreamToReadableStreamfunction. As noted intokens.ts, this appears to be auto-generated.
🟡 Minor comments (11)
lib/paginate.ts-5-8 (1)
5-8: Index signature in PaginateResponse may cause type conflicts.The
PaginateResponseinterface has both an index signature[key: string]: Tand atotal: numberproperty. This creates a type conflict becausetotalmust also satisfy the index signature constraint. TypeScript requirestotal: numberto be assignable toT, which may cause issues whenTis notnumber.🔎 Proposed fix
-interface PaginateResponse<T = any> { - [key: string]: T; - total: number; -} +interface PaginateResponse<T = any> { + [key: string]: T | number; + total: number; +}Or consider a more explicit structure without index signature if possible.
lib/commands/types.ts-187-192 (1)
187-192: Double-wrapped actionRunner on types command.The
typesCommandis already wrapped withactionRunneron line 73, and then wrapped again on line 192. This could cause issues with error handling being applied twice.🔎 Proposed fix
export const types = new Command("types") .description("Generate types for your Appwrite project") .addArgument(typesOutputArgument) .addOption(typesLanguageOption) .addOption(typesStrictOption) - .action(actionRunner(typesCommand)); + .action(typesCommand);lib/commands/functions.ts-909-919 (1)
909-919: Makedestinationrequired or guard againstundefinedinfunctionsGetDeploymentDownload
FunctionsGetDeploymentDownloadRequestParamsmarksdestinationas optional, but the implementation assumes it’s always set:fs.writeFileSync(destination, response);From the CLI side this is enforced by
.requiredOption('--destination <path>'), but programmatic callers following the type can omitdestinationand hit a runtime error.Either:
- Make
destinationrequired in the interface, or- Guard explicitly and throw a clear error if it’s missing.
Also applies to: 944-945
lib/commands/graphql.ts-98-102 (1)
98-102: Incorrect command description: "mutation" instead of "query".Line 100 describes the
querycommand as "Execute a GraphQL mutation." This should say "Execute a GraphQL query."🔎 Proposed fix
graphql .command(`query`) - .description(`Execute a GraphQL mutation.`) + .description(`Execute a GraphQL query.`) .requiredOption(`--query <query>`, `The query or queries to execute.`)lib/commands/push.ts-1187-1192 (1)
1187-1192: Question asks for entrypoint but result is assigned to buildCommand.Lines 1189-1191 use
questionsGetEntrypoint(which prompts "Enter the entrypoint") but assign the answer tosite.buildCommand. This creates a semantic mismatch—either the question should ask for a build command instead of an entrypoint, or the assignment should use a different property that aligns with the prompt.lib/parser.ts-229-229 (1)
229-229: Typo: "whomai" should be "whoami".The description text contains a typo: "The whomai command" should be "The whoami command".
🔎 Proposed fix
- whoami: `The whomai command gives information about the currently logged-in user.`, + whoami: `The whoami command gives information about the currently logged-in user.`,lib/commands/proxy.ts-34-36 (1)
34-36: Missing command description for 'proxy'.Similar to the
tokenscommand, thecommandDescriptionsmap inlib/parser.tsdoes not include a'proxy'key, resulting in an empty description for this command.🔎 Add to lib/parser.ts commandDescriptions
export const commandDescriptions: Record<string, string> = { + proxy: `The proxy command allows you to manage custom domain proxy rules for your Appwrite project.`, account: `The account command allows you to authenticate and manage a user account.`,Committable suggestion skipped: line range outside the PR's diff.
lib/commands/tokens.ts-34-36 (1)
34-36: Missing command description for 'tokens'.The
commandDescriptionsmap inlib/parser.tsdoes not include a'tokens'key, so this command will have an empty description. Consider adding a description entry for the tokens command.🔎 Add to lib/parser.ts commandDescriptions
export const commandDescriptions: Record<string, string> = { account: `The account command allows you to authenticate and manage a user account.`, + tokens: `The tokens command allows you to manage file access tokens.`, graphql: `The graphql command allows you to query and mutate any resource type on your Appwrite server.`,lib/questions.ts-81-82 (1)
81-82: Same typo ingetEntrypointandgetInstallCommand.The
langugetypo is repeated in these functions as well.🔎 Proposed fix
const getEntrypoint = (runtime: string): string | undefined => { - const languge = runtime.split("-").slice(0, -1).join("-"); + const language = runtime.split("-").slice(0, -1).join("-"); - switch (languge) { + switch (language) {const getInstallCommand = (runtime: string): string | undefined => { - const languge = runtime.split("-").slice(0, -1).join("-"); + const language = runtime.split("-").slice(0, -1).join("-"); - switch (languge) { + switch (language) {Also applies to: 119-120
lib/questions.ts-47-50 (1)
47-50: Typo:langugeshould belanguage.The variable name is misspelled as
langugeinstead oflanguage. This typo appears ingetIgnores,getEntrypoint, andgetInstallCommandfunctions.🔎 Proposed fix for getIgnores
const getIgnores = (runtime: string): string[] => { - const languge = runtime.split("-").slice(0, -1).join("-"); + const language = runtime.split("-").slice(0, -1).join("-"); - switch (languge) { + switch (language) {lib/commands/account.ts-2-5 (1)
2-5: Remove unused imports from lines 2-5.The imported modules
pathLib,tar,ignore, andpromisifyare not used anywhere in this file and should be removed.
🧹 Nitpick comments (47)
lib/type-generation/languages/dart.ts (1)
1-4: Consider using ES module import syntax for consistency.The
import fs = require('fs')andimport path = require('path')syntax works but is less common in modern TypeScript. Since this PR migrates to TypeScript with ES modules, consider aligning with the ES module style used in other files.🔎 Proposed fix
-import fs = require('fs'); -import path = require('path'); +import * as fs from 'fs'; +import * as path from 'path'; import { AttributeType } from '../attribute'; import { LanguageMeta, Attribute, Collection } from './language';lib/commands/pull.ts (5)
33-64: Actions map has loose typing for action callbacks.The
actionsmap is typed asRecord<string, (options?: any) => Promise<void>>, but the individual functions have different signatures (e.g.,pullFunctionsexpectsPullFunctionsOptions). This works at runtime but loses type safety for the options parameter.Consider creating a union type or using a discriminated union for stronger typing if you want to ensure type safety when calling these actions with specific options.
66-81: Empty catch block with rethrow is redundant.The
try/catchblock on lines 69-80 catches the exception only to rethrow it, which provides no benefit.🔎 Proposed fix
const pullSettings = async (): Promise<void> => { log("Pulling project settings ..."); - try { - let response = await projectsGet({ - parseOutput: false, - projectId: localConfig.getProject().projectId - }); - - localConfig.setProject(response.$id, response.name, response); - - success(`Successfully pulled ${chalk.bold('all')} project settings.`); - } catch (e) { - throw e; - } + let response = await projectsGet({ + parseOutput: false, + projectId: localConfig.getProject().projectId + }); + + localConfig.setProject(response.$id, response.name, response); + + success(`Successfully pulled ${chalk.bold('all')} project settings.`); }
154-155: Silent catch blocks swallow errors.Empty
catchblocks at lines 154-155 and 186-187 silently swallow errors without any logging, making debugging difficult when API calls fail.Consider at least logging the error at a debug level:
- } catch { - } + } catch (e) { + // Deployment listing failed; proceed without deployment + }
189-189: Consider more specific typing forholdingVars.The variable
holdingVarsis implicitly typed asanyfromfunc['vars'], and thenmapcasts items toany. Consider defining a proper type for function variables.
267-268: Consistent silent catch blocks in pullSites.Same issue as in
pullFunctions- empty catch blocks silently swallow errors. Consider adding at least a comment explaining why the error is being ignored.Also applies to: 298-300
lib/paginate.ts (1)
10-16: Return type union creates awkward consumer experience.The function returns either
T[]orPaginateResponse<T[]>depending on whetherwrapperis empty. This forces consumers to check the return type at runtime. Consider using an options object with a discriminant or always returning a consistent shape.Also applies to: 55-62
lib/emulation/docker.ts (2)
12-19: Duplicate FunctionConfig interface differs from lib/types.ts.This file defines a local
FunctionConfiginterface that differs from the one inlib/types.ts(lines 56-72 in relevant snippets). The lib/types.ts version includes additional fields likename,execute,enabled,logging,events,schedule,timeout,vars, andscopesthat are missing here.Consider importing from
lib/types.tsand extending or picking the needed fields to avoid divergence:-interface FunctionConfig { - $id: string; - runtime: string; - path: string; - entrypoint: string; - commands: string; - ignore?: string; -} +import { FunctionConfig } from '../types';Or if you need a subset:
import { FunctionConfig as FullFunctionConfig } from '../types'; type FunctionConfig = Pick<FullFunctionConfig, '$id' | 'runtime' | 'path' | 'entrypoint' | 'commands'> & { ignore?: string };
233-264: Recursive promise pattern in waitUntilPortOpen works but could leak resources.The recursive call to
waitUntilPortOpeninside the error handler creates new promises on each retry. While functional, if the error handling path is taken many times, this could potentially lead to memory pressure in edge cases.Consider refactoring to an iterative approach with a loop for clarity and to avoid deep recursion:
async function waitUntilPortOpen(port: number, maxAttempts: number = 100): Promise<void> { for (let i = 0; i < maxAttempts; i++) { try { await tryConnect(port); return; } catch { await new Promise<void>((res) => setTimeout(res, 100)); } } throw new Error(`Port ${port} did not open after ${maxAttempts} attempts`); }lib/commands/types.ts (1)
108-122: Use ofany[]type loses type safety.Variables
collections,dataItemsare typed asany[]which defeats the purpose of TypeScript migration. Consider defining proper interfaces for these data structures.- let collections: any[] = []; + let collections: Collection[] = []; let dataSource = 'tables'; // ... - let dataItems: any[] = tables.length > 0 ? tables : collections; + let dataItems: Collection[] = tables.length > 0 ? tables : collections;lib/commands/update.ts (2)
9-9: Using require for JSON import works but could use ES module syntax.The
require('../../../package.json')works for reading the version, but for full TypeScript benefit, consider using ES module import withresolveJsonModuleenabled in tsconfig.-const { version } = require('../../../package.json'); +import packageJson from '../../../package.json'; +const { version } = packageJson;This requires
"resolveJsonModule": truein tsconfig.json.
81-91: Error message detection is fragile.Checking
e.message.includes('EEXIST')or'already installed'for success detection is brittle as these strings could change between npm/brew versions or locales.Consider checking the exit code instead, or at minimum log the full error for debugging:
} catch (e: any) { // Log full error for debugging before checking specific conditions console.debug('Update error details:', e); if (e.message.includes('EEXIST') || ...Also applies to: 103-113
lib/commands/run.ts (1)
45-52: Potential logic issue with NaN check on null value.
isNaN(null!)returnsfalsebecausenullcoerces to0. Ifportis not provided andportNumremainsnull, the check on line 50 won't catch it. However, the subsequentif(portNum)check on line 54 handles this, so it's not a runtime bug—but the NaN check is misleading and can be simplified.🔎 Suggested simplification
let portNum: number | null = null; if(port) { - portNum = +port; - } - - if(isNaN(portNum!)) { - portNum = null; + const parsed = +port; + portNum = isNaN(parsed) ? null : parsed; }lib/emulation/utils.ts (2)
99-145: Consider handling missing projectId gracefully.Line 138 uses a non-null assertion on
projectId. IflocalConfig.getProject().projectIdis undefined, this will passundefined!to the API call, which may cause confusing errors downstream.🔎 Proposed defensive check
+ const projectId = localConfig.getProject().projectId; + if (!projectId) { + throw new Error('Project ID is not configured. Run "appwrite init" first.'); + } + const functionResponse: any = await projectsCreateJWT({ - projectId: localConfig.getProject().projectId!, + projectId, scopes: projectScopes, duration: 60 * 60, parseOutput: false, });
183-192: Files array not cleared after reload event emission.The
_triggermethod emits the reload event with the currentfilesarray but doesn't clear it afterward. Thefilesarray is only cleared inlock(). Ifunlock()is called withoutlock()being called first (or if push is called between unlock and the next lock), files could be processed multiple times.🔎 Proposed fix to clear files after emission
_trigger(): void { if (this.debounce) { return; } this.debounce = setTimeout(() => { - this.events.emit('reload', { files: this.files } as QueueReloadEvent); + const filesToProcess = [...this.files]; + this.files = []; + this.events.emit('reload', { files: filesToProcess } as QueueReloadEvent); this.debounce = null; }, 300); },lib/commands/teams.ts (1)
1-13: Several imports appear unused in this file.The imports for
tar,ignore,pathLib,promisify,getAllFiles,File, andReadableStreamdon't appear to be used in the teams command module. Similarly,convertReadStreamToReadableStream(lines 15-32) is defined but not called.This is likely template-generated code, so this may be acceptable for consistency across command modules.
lib/commands/migrations.ts (2)
1-13: Same pattern of potentially unused imports.Similar to
teams.ts, several imports (tar,ignore,pathLib,promisify,getAllFiles,File,ReadableStream) and theconvertReadStreamToReadableStreamfunction appear unused in this specific command module.
156-171: Parameterescapeshadows global property.The
escapeparameter shadows the globalescapefunction. Whileescapeis deprecated, this can still cause confusion. Consider renaming toescapeCharor similar.Based on static analysis hint from Biome.
🔎 Proposed fix
interface MigrationsCreateCSVExportRequestParams { resourceId: string; filename: string; columns?: string[]; queries?: string[]; delimiter?: string; enclosure?: string; - escape?: string; + escapeChar?: string; header?: boolean; notify?: boolean; overrideForCli?: boolean; parseOutput?: boolean; sdk?: Client; } -export const migrationsCreateCSVExport = async ({resourceId,filename,columns,queries,delimiter,enclosure,escape,header,notify,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVExportRequestParams): Promise<any> => { +export const migrationsCreateCSVExport = async ({resourceId,filename,columns,queries,delimiter,enclosure,escapeChar,header,notify,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVExportRequestParams): Promise<any> => {Note: The payload assignment (line 196-198) would also need updating to map
escapeCharto the API'sescapefield:if (typeof escapeChar !== 'undefined') { payload['escape'] = escapeChar; }lib/commands/users.ts (1)
15-32: UnusedconvertReadStreamToReadableStreamhelper in users commandsThis helper isn’t used anywhere in
lib/commands/users.ts. Consider removing it here (and the related imports) or moving it to a shared utility that’s only imported by modules that actually need streaming uploads, to avoid dead code and reduce cognitive load.lib/commands/projects.ts (1)
15-32: Remove unusedconvertReadStreamToReadableStreamhelper from projects commandsThis file doesn’t use streaming uploads, but still defines
convertReadStreamToReadableStreamand imports the related dependencies. That’s effectively dead code here.Consider dropping the helper (and its supporting imports) from this module, or moving it into a shared utility that’s only imported by callers that actually need chunked uploads.
CHANGELOG.md (1)
3-6: Optional: Clarify impact of TS migration in changelogThe 13.0.0-rc.1 entry only mentions “Migrates codebase from JavaScript to TypeScript”. Since this release also introduces ESM-style named exports and typed param objects, you might want to briefly call out any breaking surface changes for consumers (e.g., import path / export changes), if they exist.
This helps downstream users understand whether they need to adjust code when upgrading.
lib/exception.ts (1)
1-20: Exception implementation looks good; consider ES-style export for consistencyThe
AppwriteExceptionclass itself is fine (name set, extra fields exposed, stack captured on V8).The file currently uses a CommonJS-style export:
export = AppwriteException;Given the rest of the codebase is moving to ES module style (
import Client from '../client';, named exports from commands), consider switching to an ES export (e.g.,export default AppwriteException) for consistency—provided it doesn’t break existing consumers thatrequire()this module.If you do keep
export =, double‑check thatlib/client.tsand any external consumers are importing it in a way that TypeScript and your bundling/emit settings support (e.g.,import AppwriteException = require('./exception');or compatible interop config).lib/commands/organizations.ts (1)
14-45: LGTM - Clean implementation following established patterns.The function correctly handles optional SDK injection, payload construction, and conditional output parsing. The renaming of
consoletoshowConsole(line 19) nicely avoids shadowing the globalconsoleobject.Minor optional nit: consider using
constinstead ofletforclient,apiPath,payload, andresponsesince none are reassigned.lib/commands/init.ts (1)
327-342: DuplicatecopyRecursiveSyncfunction.This helper is defined identically here and again in
initSite(lines 472-487). Consider extracting it to a shared utility module (e.g.,lib/utils.ts) to follow DRY principles.🔎 Suggested extraction
Add to
lib/utils.ts:export const copyRecursiveSync = (src: string, dest: string): void => { const exists = fs.existsSync(src); const stats = exists && fs.statSync(src); const isDirectory = exists && stats && stats.isDirectory(); if (isDirectory) { if (!fs.existsSync(dest)) { fs.mkdirSync(dest); } fs.readdirSync(src).forEach((childItemName) => { copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName)); }); } else { fs.copyFileSync(src, dest); } };Then import and use it in both
initFunctionandinitSite.lib/sdks.ts (1)
24-34: Minor:localConfig.getProject()is called twice.Line 27 calls
localConfig.getProject()twice in the same expression. Consider caching the result:🔎 Proposed optimization
export const sdkForProject = async (): Promise<Client> => { const client = new Client(); const endpoint = localConfig.getEndpoint() || globalConfig.getEndpoint(); - const project = localConfig.getProject().projectId ? localConfig.getProject().projectId : globalConfig.getProject(); + const localProject = localConfig.getProject(); + const project = localProject.projectId ? localProject.projectId : globalConfig.getProject(); const key = globalConfig.getKey();lib/commands/graphql.ts (1)
1-14: Multiple unused imports.Several imports appear unused in this file:
fs,pathLib,tar,ignore,promisify,getAllFiles,localConfig,globalConfig,File,ReadableStream. TheconvertReadStreamToReadableStreamfunction (lines 15-32) also appears unused.Consider removing these to reduce clutter, unless they're planned for future use.
🔎 Minimal imports needed
import Client from '../client'; import { Command } from 'commander'; import { sdkForProject } from '../sdks'; import { parse, actionRunner, commandDescriptions } from '../parser';lib/commands/console.ts (5)
1-13: Unused imports detected.Several imports are not used in this file:
fs,pathLib,tar,ignore,promisify,getAllFiles,parseInteger,localConfig, andFile. These appear to be leftover from a template or copy-paste.🔎 Proposed cleanup
-import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; +import { showConsoleLink } from '../utils'; import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; +import { sdkForProject } from '../sdks'; +import { parse, actionRunner, commandDescriptions } from '../parser';
15-32: Unused helper function.
convertReadStreamToReadableStreamis defined but never used in this file. Consider removing it to reduce dead code.
34-36: Export nameconsoleshadows the globalconsoleobject.Naming the exported Command
consoleshadows JavaScript's globalconsole, which could cause confusion and subtle bugs ifconsole.logor similar methods are used later in this module. While TypeScript may catch direct misuse, this is a maintenance hazard.Consider renaming to
consoleCommandor similar to avoid shadowing.🔎 Proposed rename
-export const console = new Command("console").description(commandDescriptions['console'] ?? '').configureHelp({ +export const consoleCommand = new Command("console").description(commandDescriptions['console'] ?? '').configureHelp({ helpWidth: process.stdout.columns || 80 })Then update command wiring at lines 99 and 107 to use
consoleCommand.
47-74: Unused parameteroverrideForCli.The
overrideForCliparameter is destructured from the input but never used in the function body. Either remove it from the interface and function signature, or implement the intended behavior.Additionally, Line 59's
let response = undefined;is redundant since it's immediately assigned on line 61.🔎 Proposed cleanup
-export const consoleGetResource = async ({value,type,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ConsoleGetResourceRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; +export const consoleGetResource = async ({value, type, parseOutput = true, sdk = undefined, console: showConsole}: ConsoleGetResourceRequestParams): Promise<any> => { + const client = sdk ?? await sdkForProject(); let apiPath = '/console/resources'; let payload = {}; if (typeof value !== 'undefined') { payload['value'] = value; } if (typeof type !== 'undefined') { payload['type'] = type; } - let response = undefined; - - response = await client.call('get', apiPath, { + const response = await client.call('get', apiPath, { }, payload);
75-98: Same issues asconsoleGetResource.The
overrideForCliparameter is unused, andlet response = undefined;is redundant. Apply similar cleanup as suggested for the previous function.lib/client.ts (3)
11-29: Unused constantCHUNK_SIZE.The
CHUNK_SIZEconstant on line 12 is defined but never used in this file. Consider removing it or adding a TODO if it's intended for future chunked upload functionality.
148-196: Type safety concern in URLSearchParams construction.On line 161,
Client.flatten(params)returnsRecord<string, unknown>, butURLSearchParamsexpectsRecord<string, string>. Non-string values may be coerced to[object Object]or similar.🔎 Proposed fix
if (method.toUpperCase() === 'GET') { - url.search = new URLSearchParams(Client.flatten(params) as Record<string, string>).toString(); + const flatParams = Client.flatten(params); + const stringParams: Record<string, string> = {}; + for (const [key, value] of Object.entries(flatParams)) { + stringParams[key] = String(value); + } + url.search = new URLSearchParams(stringParams).toString(); }
207-214: Side-effect in generic HTTP call method.Automatically removing sessions (lines 207-213) when receiving a 401 with
user_more_factors_requiredis a significant side effect in a low-level HTTP client method. This behavior might surprise callers who expect thecallmethod to only perform the HTTP request.Consider moving this logic to a higher-level wrapper or documenting this behavior clearly.
lib/commands/push.ts (1)
1-97: UnusedJSONbigNativeconstant.
JSONbigNativeis initialized on line 97 but never used in the file. Consider removing it.lib/config.ts (1)
285-308: Inconsistent merge behavior acrossaddXmethods.
addSite(andaddFunction) merge existing entities with new props using spread operator ({ ...sites[i], ...props }), whileaddCollection,addTable,addBucket, and others completely replace existing entries (collections[i] = props).This inconsistency could lead to unexpected data loss if users expect merge behavior. Consider standardizing on one approach.
lib/parser.ts (1)
113-158: Control flow issue inparseErrorwith async IIFE.The async IIFE on lines 115-148 calls
process.exit(1)inside it, but since the IIFE is not awaited, the code on line 156 (process.exit(1)) could potentially execute before the async block completes in edge cases. However, since both paths end inprocess.exit(1), this is functionally correct but the pattern is slightly confusing.Additionally, line 128 accesses
(cliConfig.reportData as any).data.argswhich relies on runtime structure without type safety. Consider defining a proper type forreportDatato avoid potential runtime errors if the structure changes.lib/commands/tokens.ts (1)
1-13: Unused imports detected.Several imports are not used in this file:
fs,pathLib,tar,ignore,promisify,getAllFiles,localConfig,File, andReadableStream. Similarly, theconvertReadStreamToReadableStreamfunction (lines 15-32) is defined but never called.This appears to be auto-generated boilerplate. If this is intentional for consistency across command files, consider adding a comment or configuring the linter to ignore these. Otherwise, removing unused imports would reduce bundle size and improve clarity.
lib/commands/locale.ts (1)
38-42: Consider consolidating identical request param interfaces.All the
Locale*RequestParamsinterfaces in this file share the same structure with onlyoverrideForCli?,parseOutput?, andsdk?properties. While this is likely auto-generated code, consolidating into a shared base interface would reduce duplication:interface BaseLocaleRequestParams { overrideForCli?: boolean; parseOutput?: boolean; sdk?: Client; }However, if this is auto-generated, maintaining separate interfaces may be intentional for future extensibility.
lib/questions.ts (3)
17-17: Unused variable:JSONbigConfigis defined but never used.The
JSONbigConfigconstant is initialized but not referenced anywhere in the file. Consider removing it or utilizing it whereJSONbigis needed.🔎 Proposed fix
-const JSONbigConfig = JSONbig({ storeAsString: false });
682-696: Potential runtime error ifsessionsarray is empty.The
reducecall on line 684 will throw aTypeErrorifsessionsis an empty array since no initial value is provided. While thechoicesfunction is likely only called when sessions exist (based on thewhencondition at line 647), adding a guard or initial value would make this more robust.🔎 Proposed defensive fix
- const longestEmail = sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length; + const longestEmail = sessions.length > 0 + ? sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length + : 0;
737-751: Same empty array risk inquestionsLogout.The same
reducepattern without an initial value is used inquestionsLogout, which could throw ifsessionsis unexpectedly empty.lib/commands/health.ts (1)
1-13: Unused imports detected.Several imports (
fs,pathLib,tar,ignore,promisify,getAllFiles,File) are not used in this file. TheconvertReadStreamToReadableStreamhelper function is also defined but never called. These appear to be copy-pasted boilerplate from a template.🔎 Proposed fix - remove unused imports and helper
-import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; +import { showConsoleLink } from '../utils'; import { Command } from 'commander'; import { sdkForProject, sdkForConsole } from '../sdks'; import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -}lib/commands/storage.ts (1)
107-110: Unusual pattern:permissions === true ? [] : permissionsThis pattern suggests that the CLI parser might pass
truewhen an option is specified without a value. While this works as a workaround, consider adding a comment explaining the behavior or handling this at the CLI option parsing level for clarity.Also applies to: 120-123
lib/commands/vcs.ts (1)
1-32: Unused imports and helper function.Similar to
health.ts, this file has unused imports (fs,pathLib,tar,ignore,promisify,getAllFiles,File,ReadableStream) and an unusedconvertReadStreamToReadableStreamfunction that should be removed.🔎 Proposed fix - remove unused code
-import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; +import { showConsoleLink } from '../utils'; import { Command } from 'commander'; import { sdkForProject, sdkForConsole } from '../sdks'; import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -}lib/commands/account.ts (2)
1-5: Prefer modern ES module import syntax.Lines 1-5 use TypeScript's legacy CommonJS import syntax (
import fs = require('fs')), while lines 6-12 use modern ES module syntax. For consistency and better alignment with ES module standards, convert the legacy imports to modern syntax.🔎 Proposed refactor
-import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); +import * as fs from 'fs'; +import * as pathLib from 'path'; +import * as tar from 'tar'; +import * as ignore from 'ignore'; import { promisify } from 'util';
1368-1418: Consider extracting common logic to reduce duplication.The functions
accountCreateEmailVerificationandaccountCreateVerification(lines 1368-1418) have identical implementations. While the duplication is intentional for backward compatibility (asaccountCreateVerificationis deprecated), extracting the shared logic into a common helper function would improve maintainability.🔎 Example refactor
const _createEmailVerificationInternal = async ({url, parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateEmailVerificationRequestParams): Promise<any> => { let client = !sdk ? await sdkForProject() : sdk; let apiPath = '/account/verifications/email'; let payload = {}; if (typeof url !== 'undefined') { payload['url'] = url; } let response = undefined; response = await client.call('post', apiPath, { 'content-type': 'application/json', }, payload); if (parseOutput) { parse(response) } return response; } export const accountCreateEmailVerification = _createEmailVerificationInternal; export const accountCreateVerification = _createEmailVerificationInternal;Note: The same pattern applies to
accountUpdateEmailVerificationandaccountUpdateVerification(lines 1427-1484).
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (76)
CHANGELOG.mdREADME.mddocs/examples/databases/upsert-document.mdindex.jsindex.tsinstall.ps1install.shlib/client.jslib/client.tslib/commands/account.tslib/commands/console.jslib/commands/console.tslib/commands/databases.tslib/commands/functions.tslib/commands/generic.tslib/commands/graphql.jslib/commands/graphql.tslib/commands/health.tslib/commands/init.tslib/commands/locale.tslib/commands/messaging.tslib/commands/migrations.tslib/commands/organizations.jslib/commands/organizations.tslib/commands/project.tslib/commands/projects.tslib/commands/proxy.tslib/commands/pull.tslib/commands/push.tslib/commands/run.tslib/commands/sites.tslib/commands/storage.tslib/commands/tables-db.tslib/commands/teams.tslib/commands/tokens.tslib/commands/types.tslib/commands/update.tslib/commands/users.tslib/commands/vcs.tslib/config.jslib/config.tslib/emulation/docker.tslib/emulation/utils.jslib/emulation/utils.tslib/exception.jslib/exception.tslib/id.tslib/paginate.tslib/parser.jslib/parser.tslib/questions.tslib/sdks.jslib/sdks.tslib/spinner.tslib/type-generation/attribute.jslib/type-generation/attribute.tslib/type-generation/languages/csharp.tslib/type-generation/languages/dart.tslib/type-generation/languages/java.tslib/type-generation/languages/javascript.jslib/type-generation/languages/javascript.tslib/type-generation/languages/kotlin.jslib/type-generation/languages/kotlin.tslib/type-generation/languages/language.jslib/type-generation/languages/language.tslib/type-generation/languages/php.tslib/type-generation/languages/swift.tslib/type-generation/languages/typescript.jslib/type-generation/languages/typescript.tslib/types.tslib/utils.tslib/validations.jslib/validations.tspackage.jsonscoop/appwrite.config.jsontsconfig.json
💤 Files with no reviewable changes (11)
- lib/emulation/utils.js
- lib/type-generation/attribute.js
- lib/commands/organizations.js
- lib/sdks.js
- lib/commands/graphql.js
- lib/exception.js
- index.js
- lib/parser.js
- lib/config.js
- lib/client.js
- lib/commands/console.js
🧰 Additional context used
🧬 Code graph analysis (23)
lib/commands/organizations.ts (3)
lib/sdks.ts (1)
sdkForProject(24-55)lib/utils.ts (1)
showConsoleLink(111-153)lib/parser.ts (1)
parse(21-48)
lib/type-generation/languages/dart.ts (2)
lib/type-generation/languages/language.ts (2)
Attribute(4-15)Collection(17-21)lib/type-generation/attribute.ts (1)
AttributeType(1-15)
lib/sdks.ts (2)
lib/commands/generic.ts (1)
client(242-316)lib/config.ts (2)
globalConfig(843-843)localConfig(842-842)
lib/commands/graphql.ts (3)
lib/parser.ts (3)
commandDescriptions(206-236)parse(21-48)actionRunner(160-168)lib/commands/generic.ts (1)
client(242-316)lib/sdks.ts (1)
sdkForProject(24-55)
lib/type-generation/languages/csharp.ts (2)
lib/type-generation/languages/language.ts (2)
Attribute(4-15)Collection(17-21)lib/type-generation/attribute.ts (1)
AttributeType(1-15)
lib/emulation/utils.ts (4)
lib/parser.ts (1)
log(184-186)lib/commands/users.ts (2)
usersGet(545-566)usersCreateJWT(632-656)lib/commands/projects.ts (1)
projectsCreateJWT(852-877)lib/config.ts (1)
localConfig(842-842)
lib/commands/update.ts (2)
lib/parser.ts (3)
success(196-198)hint(192-194)error(200-202)lib/spinner.ts (1)
update(86-89)
lib/parser.ts (3)
lib/types.ts (1)
CliConfig(1-9)lib/config.ts (1)
globalConfig(843-843)lib/utils.ts (1)
isCloud(318-322)
lib/emulation/docker.ts (2)
lib/types.ts (1)
FunctionConfig(57-73)lib/parser.ts (2)
error(200-202)success(196-198)
lib/commands/push.ts (3)
lib/config.ts (2)
keys(156-158)localConfig(842-842)lib/utils.ts (1)
checkDeployConditions(103-109)lib/questions.ts (1)
questionsGetEntrypoint(931-944)
lib/type-generation/languages/java.ts (2)
lib/type-generation/languages/language.ts (2)
Attribute(4-15)Collection(17-21)lib/type-generation/attribute.ts (1)
AttributeType(1-15)
lib/commands/types.ts (2)
lib/parser.ts (2)
actionRunner(160-168)log(184-186)lib/type-generation/languages/language.ts (1)
Collection(17-21)
lib/commands/generic.ts (3)
lib/parser.ts (5)
log(184-186)success(196-198)hint(192-194)commandDescriptions(206-236)actionRunner(160-168)lib/commands/account.ts (1)
account(34-36)lib/config.ts (1)
globalConfig(843-843)
lib/config.ts (1)
lib/types.ts (4)
ConfigData(27-29)ProjectConfigData(46-55)GlobalConfigData(38-44)SessionData(31-36)
lib/client.ts (1)
lib/types.ts (4)
Headers(11-13)RequestParams(15-17)ResponseType(25-25)FileUpload(19-23)
lib/commands/console.ts (4)
lib/parser.ts (3)
commandDescriptions(206-236)parse(21-48)actionRunner(160-168)lib/commands/generic.ts (1)
client(242-316)lib/sdks.ts (1)
sdkForProject(24-55)lib/utils.ts (1)
showConsoleLink(111-153)
lib/commands/tokens.ts (1)
lib/parser.ts (2)
commandDescriptions(206-236)parseBool(178-182)
lib/commands/project.ts (1)
lib/parser.ts (2)
commandDescriptions(206-236)parseBool(178-182)
lib/commands/vcs.ts (1)
lib/parser.ts (1)
parseBool(178-182)
lib/commands/proxy.ts (1)
lib/parser.ts (2)
commandDescriptions(206-236)parseBool(178-182)
lib/commands/sites.ts (1)
lib/parser.ts (2)
commandDescriptions(206-236)parseBool(178-182)
lib/commands/functions.ts (1)
lib/parser.ts (2)
commandDescriptions(206-236)parseBool(178-182)
lib/commands/projects.ts (1)
lib/parser.ts (3)
commandDescriptions(206-236)parseBool(178-182)actionRunner(160-168)
🪛 Biome (2.1.2)
lib/type-generation/languages/dart.ts
[error] 63-63: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
lib/type-generation/languages/csharp.ts
[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
lib/type-generation/languages/java.ts
[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
lib/commands/migrations.ts
[error] 171-171: Do not shadow the global "escape" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
| appwrite databases upsert-document \ | ||
| --database-id <DATABASE_ID> \ | ||
| --collection-id <COLLECTION_ID> \ | ||
| --document-id <DOCUMENT_ID> \ | ||
| --data '{ "key": "value" }' | ||
| --document-id <DOCUMENT_ID> |
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.
Add --data parameter to the upsert-document example.
The upsertDocument operation requires a data parameter containing the document attributes to be created or updated. The example must include this parameter with sample JSON data for the command to function correctly:
appwrite databases upsert-document \
--database-id <DATABASE_ID> \
--collection-id <COLLECTION_ID> \
--document-id <DOCUMENT_ID> \
--data '{"key": "value"}'
🤖 Prompt for AI Agents
In docs/examples/databases/upsert-document.md around lines 1 to 4, the example
command is missing the required --data parameter; update the example to include
a --data argument with sample JSON (e.g., --data '{"key":"value"}') so the
upsert-document command supplies the document attributes needed for
create/update.
| import fs = require('fs'); | ||
| import pathLib = require('path'); | ||
| import tar = require('tar'); | ||
| import ignore = require('ignore'); | ||
| import { promisify } from 'util'; | ||
| import Client from '../client'; | ||
| import { getAllFiles, showConsoleLink } from '../utils'; | ||
| import { Command } from 'commander'; | ||
| import { sdkForProject, sdkForConsole } from '../sdks'; | ||
| import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; | ||
| import { localConfig, globalConfig } from '../config'; | ||
| import { File } from 'undici'; | ||
| import { ReadableStream } from 'stream/web'; | ||
|
|
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the file exists and examine the imports and references
if [ -f "lib/commands/account.ts" ]; then
echo "=== File exists, checking size ==="
wc -l lib/commands/account.ts
echo ""
echo "=== Checking imports section (lines 1-20) ==="
head -20 lib/commands/account.ts
echo ""
echo "=== Searching for AuthenticatorType references ==="
grep -n "AuthenticatorType" lib/commands/account.ts | head -10
echo ""
echo "=== Searching for AuthenticationFactor references ==="
grep -n "AuthenticationFactor" lib/commands/account.ts | head -10
echo ""
echo "=== Searching for OAuthProvider references ==="
grep -n "OAuthProvider" lib/commands/account.ts | head -10
else
echo "File not found"
fiRepository: appwrite/sdk-for-cli
Length of output: 1357
🏁 Script executed:
#!/bin/bash
# Check the context around the references to understand how they're being used
echo "=== Context around AuthenticatorType (line 311) ==="
sed -n '308,315p' lib/commands/account.ts
echo ""
echo "=== Context around AuthenticationFactor (line 393) ==="
sed -n '390,397p' lib/commands/account.ts
echo ""
echo "=== Context around OAuthProvider (line 916) ==="
sed -n '913,920p' lib/commands/account.tsRepository: appwrite/sdk-for-cli
Length of output: 730
Add missing type imports from appwrite module.
The code references types AuthenticatorType (lines 311, 337, 367), AuthenticationFactor (line 393), and OAuthProvider (lines 916, 1292) that are not imported. Import these types from the appwrite module to resolve compilation errors:
import { AuthenticatorType, AuthenticationFactor, OAuthProvider } from 'appwrite';🤖 Prompt for AI Agents
In lib/commands/account.ts around lines 1 to 14, the file uses Appwrite types
AuthenticatorType (lines ~311, 337, 367), AuthenticationFactor (~393) and
OAuthProvider (~916, 1292) but does not import them; add a named import from the
'appwrite' module to include AuthenticatorType, AuthenticationFactor and
OAuthProvider at the top of the file so the referenced types resolve and
TypeScript compiles.
| interface ConsoleGetResourceRequestParams { | ||
| value: string; | ||
| type: ConsoleResourceType; | ||
| overrideForCli?: boolean; | ||
| parseOutput?: boolean; | ||
| sdk?: Client; | ||
| console?: boolean; | ||
| } |
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.
Missing type definition: ConsoleResourceType.
The interface references ConsoleResourceType on line 40, but this type is never imported or defined in the file. This will cause a TypeScript compilation error.
🔎 Proposed fix
Either import the type if it exists elsewhere, or define it locally:
+type ConsoleResourceType = string; // or the appropriate union type
+
interface ConsoleGetResourceRequestParams {
value: string;
type: ConsoleResourceType;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
console?: boolean;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| interface ConsoleGetResourceRequestParams { | |
| value: string; | |
| type: ConsoleResourceType; | |
| overrideForCli?: boolean; | |
| parseOutput?: boolean; | |
| sdk?: Client; | |
| console?: boolean; | |
| } | |
| type ConsoleResourceType = string; // or the appropriate union type | |
| interface ConsoleGetResourceRequestParams { | |
| value: string; | |
| type: ConsoleResourceType; | |
| overrideForCli?: boolean; | |
| parseOutput?: boolean; | |
| sdk?: Client; | |
| console?: boolean; | |
| } |
🤖 Prompt for AI Agents
In lib/commands/console.ts around lines 38-45, the interface references
ConsoleResourceType but that type is not defined or imported; add a proper type
declaration or import to fix the TypeScript error — either import
ConsoleResourceType from the module where it is declared (e.g., add an import
line at the top importing ConsoleResourceType from the package/file that defines
it) or define a local type/union named ConsoleResourceType in this file
(matching the expected values) and use that in the interface.
| interface FunctionsCreateDeploymentRequestParams { | ||
| functionId: string; | ||
| code: string; | ||
| activate: boolean; | ||
| entrypoint?: string; | ||
| commands?: string; | ||
| overrideForCli?: boolean; | ||
| parseOutput?: boolean; | ||
| sdk?: Client; | ||
| onProgress?: (progress: number) => void; | ||
| } |
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.
Resolve type mismatches in functionsCreateDeployment (code param and onProgress callback)
Two issues here:
codeparameter re-typed at runtime
FunctionsCreateDeploymentRequestParams declares:
code: string;but inside functionsCreateDeployment you later do:
code = { type: 'file', stream, filename: ..., size: ... };
const size = code.size;
for await (const chunk of code.stream) { ... }This won’t type‑check in TS (assigning an object to a string), and it makes the runtime shape of code unclear to consumers.
Prefer keeping the param as a path string and introducing a separate local variable for the file object, e.g.:
Sketch of safer approach
export const functionsCreateDeployment = async ({ functionId, code: codePath, ... }: FunctionsCreateDeploymentRequestParams) => {
const folderPath = fs.realpathSync(codePath);
// ...
const filePath = fs.realpathSync(archivePath);
const nodeStream = fs.createReadStream(filePath);
const stream = convertReadStreamToReadableStream(nodeStream);
const fileCode = {
type: 'file' as const,
stream,
filename: pathLib.basename(filePath),
size: fs.statSync(filePath).size,
};
payload.code = fileCode;
const size = fileCode.size;
// use fileCode.stream for iteration instead of reusing `code`
};onProgresscallback type doesn’t match the actual argument
The interface currently has:
onProgress?: (progress: number) => void;but you invoke it as:
onProgress({
$id: response['$id'],
progress: ...,
sizeUploaded: end + 1,
chunksTotal: response['chunksTotal'],
chunksUploaded: response['chunksUploaded']
});This will surprise TS consumers expecting a number. Define a specific shape instead:
Proposed callback type update
interface FunctionsCreateDeploymentRequestParams {
@@
- onProgress?: (progress: number) => void;
+ onProgress?: (state: {
+ $id: string;
+ progress: number;
+ sizeUploaded: number;
+ chunksTotal: number;
+ chunksUploaded: number;
+ }) => void;
}Also applies to: 581-642, 690-699
🤖 Prompt for AI Agents
In lib/commands/functions.ts around lines 569-579 (and similarly 581-642,
690-699), the FunctionsCreateDeploymentRequestParams incorrectly types `code` as
a string while the function reassigns it to a file object and also types
`onProgress` as a number-only callback while invoking it with an object; change
the `code` param to remain a path string (e.g., `code: string` passed in as
`codePath`) and create a separate local file object (e.g., `fileCode`) that
contains the stream, filename and size which you assign to the payload and
iterate over, and change the `onProgress` type to accept a typed progress object
(define a small interface for { $id?: string; progress: number; sizeUploaded?:
number; chunksTotal?: number; chunksUploaded?: number }) and update all
`onProgress` invocations and uses to pass that object shape instead of a number.
| interface GraphqlQueryRequestParams { | ||
| query: object; | ||
| overrideForCli?: boolean; | ||
| parseOutput?: boolean; | ||
| sdk?: Client; | ||
| } |
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.
Type mismatch: query is typed as object but used as a string.
The interface declares query: object, but line 51 calls JSON.parse(query), which expects a string. This will cause a runtime error if an actual object is passed, or a TypeScript error if a string is passed.
🔎 Proposed fix
interface GraphqlQueryRequestParams {
- query: object;
+ query: string;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}And similarly for GraphqlMutationRequestParams on lines 68-73.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| interface GraphqlQueryRequestParams { | |
| query: object; | |
| overrideForCli?: boolean; | |
| parseOutput?: boolean; | |
| sdk?: Client; | |
| } | |
| interface GraphqlQueryRequestParams { | |
| query: string; | |
| overrideForCli?: boolean; | |
| parseOutput?: boolean; | |
| sdk?: Client; | |
| } |
🤖 Prompt for AI Agents
In lib/commands/graphql.ts around lines 38-43 (and similarly for
GraphqlMutationRequestParams at lines ~68-73), the interface currently types
`query` as object but the code treats it as a JSON string (calling
JSON.parse(query)). Change the `query` type to `string` (or to `string | object`
and add runtime handling: if typeof query === 'string' parse it, else use it
directly) for both Query and Mutation request params so types match usage and
avoid runtime/TS errors.
| interface StorageGetUsageRequestParams { | ||
| range?: UsageRange; | ||
| overrideForCli?: boolean; | ||
| parseOutput?: boolean; | ||
| sdk?: Client; | ||
| } |
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.
Undefined type UsageRange.
The UsageRange type is used in StorageGetUsageRequestParams and StorageGetBucketUsageRequestParams but is not imported.
Also applies to: 736-743
🤖 Prompt for AI Agents
In lib/commands/storage.ts around lines 708-713 (and similarly 736-743) the
interface fields reference an undefined type UsageRange; locate the module that
declares UsageRange in the codebase and add an import for it at the top of this
file (for example: import { UsageRange } from '<correct-path-to-definition>'),
or alternatively replace UsageRange with the correct, already-imported type if
it was renamed; ensure the import path is correct and run TypeScript to verify
the error is resolved.
| interface VcsCreateRepositoryDetectionRequestParams { | ||
| installationId: string; | ||
| providerRepositoryId: string; | ||
| type: VCSDetectionType; | ||
| providerRootDirectory?: string; | ||
| overrideForCli?: boolean; | ||
| parseOutput?: boolean; | ||
| sdk?: Client; | ||
| } |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the vcs.ts file structure and imports
cat -n lib/commands/vcs.ts | head -50
echo "---"
# Search for VCSDetectionType definition in the entire codebase
rg -n "type VCSDetectionType|enum VCSDetectionType" --type tsRepository: appwrite/sdk-for-cli
Length of output: 2170
🏁 Script executed:
#!/bin/bash
# Search for VCSDetectionType anywhere in the codebase
echo "=== Searching for VCSDetectionType definition ==="
rg "VCSDetectionType" --type ts
echo ""
echo "=== Checking for imports with asterisk or specific type imports ==="
rg "import.*VCSDetectionType|export.*VCSDetectionType" --type ts
echo ""
echo "=== Looking at vcs.ts file around line 76-84 ==="
sed -n '70,90p' lib/commands/vcs.tsRepository: appwrite/sdk-for-cli
Length of output: 1008
🏁 Script executed:
#!/bin/bash
# Search entire codebase for VCSDetectionType definition
echo "=== Searching entire codebase for VCSDetectionType ==="
rg "type VCSDetectionType|enum VCSDetectionType" --type ts -B 2 -A 2
echo ""
echo "=== Searching in all files, not just TypeScript ==="
rg "VCSDetectionType" -B 2 -A 2
echo ""
echo "=== Check if it's defined in lib/types or similar ==="
find lib -name "*.ts" -type f | head -20Repository: appwrite/sdk-for-cli
Length of output: 1198
🏁 Script executed:
#!/bin/bash
# Check if VCSDetectionType might be in Client type definitions
echo "=== Checking client.ts for VCSDetectionType ==="
rg "VCSDetectionType" lib/client.ts
echo ""
echo "=== Check for type definitions directory ==="
find . -path ./node_modules -prune -o -name "*.d.ts" -type f -print | head -20
echo ""
echo "=== Search all TypeScript files for VCSDetectionType ==="
git ls-files "*.ts" "*.d.ts" | xargs rg "VCSDetectionType" 2>/dev/null | grep -v "lib/commands/vcs.ts" || echo "Not found outside vcs.ts"Repository: appwrite/sdk-for-cli
Length of output: 240
Undefined type VCSDetectionType will cause TypeScript compilation error.
The VCSDetectionType type is used in VcsCreateRepositoryDetectionRequestParams (line 41) and VcsListRepositoriesRequestParams (line 78) but is neither imported nor defined in the file. Add the missing type definition or import statement.
🤖 Prompt for AI Agents
In lib/commands/vcs.ts around lines 38–46 (and also referenced at line 78), the
type VCSDetectionType is used but undefined; fix this by either adding an import
for VCSDetectionType from the module where your VCS/shared types are declared
(the same module that exports other VCS types used in this file) or by declaring
and exporting the appropriate type alias/enum locally in this file that matches
the expected values, then update the import/exports accordingly and re-run
TypeScript to ensure the compilation error is resolved.
| case AttributeType.RELATIONSHIP: | ||
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | ||
| if (!relatedCollection) { | ||
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | ||
| } | ||
| type = LanguageMeta.toPascalCase(relatedCollection.name); | ||
| if ( | ||
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | ||
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | ||
| attribute.relationType === 'manyToMany' | ||
| ) { | ||
| type = `List<${type}>`; | ||
| } | ||
| break; |
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 | 🟠 Major
Wrap the RELATIONSHIP case body in a block to fix scope issue.
The const relatedCollection declaration inside the switch case can be erroneously accessed by other cases. This is flagged by the linter and is a JavaScript/TypeScript best practice issue.
🔎 Proposed fix
case AttributeType.RELATIONSHIP:
+ {
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
+ }🧰 Tools
🪛 Biome (2.1.2)
[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In lib/type-generation/languages/csharp.ts around lines 25 to 38, the
RELATIONSHIP switch case declares const relatedCollection which leaks scope to
other cases and triggers a linter error; fix by wrapping the entire case body in
its own block (add { ... } around the existing case logic) so relatedCollection
and any other local variables are block-scoped, keep the existing logic and the
break inside that block unchanged.
| case AttributeType.RELATIONSHIP: | ||
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | ||
| if (!relatedCollection) { | ||
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | ||
| } | ||
| type = LanguageMeta.toPascalCase(relatedCollection.name); | ||
| if ( | ||
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | ||
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | ||
| attribute.relationType === 'manyToMany' | ||
| ) { | ||
| type = `List<${type}>`; | ||
| } | ||
| break; |
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 | 🟠 Major
Wrap the RELATIONSHIP case body in a block to fix scope issue.
Same issue as in the C# generator - the const relatedCollection declaration should be scoped to this case block.
🔎 Proposed fix
case AttributeType.RELATIONSHIP:
+ {
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case AttributeType.RELATIONSHIP: | |
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | |
| if (!relatedCollection) { | |
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | |
| } | |
| type = LanguageMeta.toPascalCase(relatedCollection.name); | |
| if ( | |
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | |
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | |
| attribute.relationType === 'manyToMany' | |
| ) { | |
| type = `List<${type}>`; | |
| } | |
| break; | |
| case AttributeType.RELATIONSHIP: | |
| { | |
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | |
| if (!relatedCollection) { | |
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | |
| } | |
| type = LanguageMeta.toPascalCase(relatedCollection.name); | |
| if ( | |
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | |
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | |
| attribute.relationType === 'manyToMany' | |
| ) { | |
| type = `List<${type}>`; | |
| } | |
| break; | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 63-63: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In lib/type-generation/languages/dart.ts around lines 62 to 75, the RELATIONSHIP
case declares const relatedCollection at switch scope which can cause a scoping
conflict; wrap the entire case body in a block (add { ... } immediately after
the case label and before the break) so relatedCollection and any other locals
are block-scoped, keeping existing logic for computing type and list wrapping
unchanged.
| case AttributeType.RELATIONSHIP: | ||
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | ||
| if (!relatedCollection) { | ||
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | ||
| } | ||
| type = LanguageMeta.toPascalCase(relatedCollection.name); | ||
| if ( | ||
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | ||
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | ||
| attribute.relationType === 'manyToMany' | ||
| ) { | ||
| type = 'List<' + type + '>'; | ||
| } | ||
| break; |
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 | 🟠 Major
Wrap the RELATIONSHIP case body in a block to fix scope issue.
Same issue as in the other language generators - the const relatedCollection declaration should be scoped to this case block.
🔎 Proposed fix
case AttributeType.RELATIONSHIP:
+ {
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = 'List<' + type + '>';
}
break;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case AttributeType.RELATIONSHIP: | |
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | |
| if (!relatedCollection) { | |
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | |
| } | |
| type = LanguageMeta.toPascalCase(relatedCollection.name); | |
| if ( | |
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | |
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | |
| attribute.relationType === 'manyToMany' | |
| ) { | |
| type = 'List<' + type + '>'; | |
| } | |
| break; | |
| case AttributeType.RELATIONSHIP: | |
| { | |
| const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); | |
| if (!relatedCollection) { | |
| throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); | |
| } | |
| type = LanguageMeta.toPascalCase(relatedCollection.name); | |
| if ( | |
| (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || | |
| (attribute.relationType === 'manyToOne' && attribute.side === 'child') || | |
| attribute.relationType === 'manyToMany' | |
| ) { | |
| type = 'List<' + type + '>'; | |
| } | |
| break; | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In lib/type-generation/languages/java.ts around lines 25 to 38, the case for
AttributeType.RELATIONSHIP declares a const (relatedCollection) at case scope
which can leak into other cases; wrap the entire case body in a block by adding
an opening brace after `case AttributeType.RELATIONSHIP:` and a closing brace
before the `break;` so `relatedCollection` and any other declarations are
properly scoped to this case only.
This PR contains updates to the Command Line SDK for version 13.0.0-rc.1.
Summary by CodeRabbit
New Features
Documentation
--dataflag from upsert-document CLI example.✏️ Tip: You can customize this high-level summary in your review settings.