Skip to content

refactor: add type annotations and clean up code - #102

Merged
hzhangxyz merged 1 commit into
mainfrom
dev/enhance-code
Mar 12, 2026
Merged

refactor: add type annotations and clean up code#102
hzhangxyz merged 1 commit into
mainfrom
dev/enhance-code

Conversation

@hzhangxyz

@hzhangxyz hzhangxyz commented Mar 12, 2026

Copy link
Copy Markdown
Member
  • Add type hints to Python functions and TypeScript modules
  • Fix variable reference bug in egraph.ts lhs/rhs extraction
  • Simplify input validation logic in input/load modules
  • Remove unused imports across modules
  • Improve database initialization flow in main.ts

close #100

- Add type hints to Python functions and TypeScript modules
- Fix variable reference bug in egraph.ts lhs/rhs extraction
- Simplify input validation logic in input/load modules
- Remove unused imports across modules
- Improve database initialization flow in main.ts
Copilot AI review requested due to automatic review settings March 12, 2026 02:48
@hzhangxyz
hzhangxyz merged commit c72e071 into main Mar 12, 2026
31 of 32 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the DDSS CLI/components to add type annotations (TypeScript + Python) and simplify component wiring while cleaning up some rule parsing/extraction logic.

Changes:

  • Added/updated type annotations across TS and Python entrypoints/modules.
  • Centralized DB initialization in ddss/main.ts and standardized component main() signatures to accept a Sequelize/sessionmaker.
  • Fixed egraph.ts LHS/RHS extraction logic and simplified input validation in Python loaders/interactive input.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ddss/utility.ts Adds return type to patchStdout (unpatch function).
ddss/search.ts Removes unused DB init import; adds return type; minor variable cleanup.
ddss/search.py Adds async_sessionmaker[AsyncSession] annotation to main.
ddss/output.ts Removes unused DB init import; adds return type.
ddss/output.py Adds async_sessionmaker[AsyncSession] annotation to main.
ddss/orm.ts Removes unused type import.
ddss/main.ts Standardizes component signatures and moves DB init into run; makes cli async.
ddss/main.py Adds typing for component map; changes unsupported-component handling to return.
ddss/load.ts Refactors parsing/insertion path (currently introduces a type mismatch bug).
ddss/load.py Simplifies empty/comment line filtering; adds sessionmaker type annotation.
ddss/input.ts Refactors parsing/insertion path (currently introduces a type mismatch bug).
ddss/input.py Simplifies empty/comment line filtering; adds sessionmaker type annotation.
ddss/egraph.ts Fixes LHS/RHS extraction to use the correct list term.
ddss/egg.ts Removes unused DB init import; adds return type.
ddss/egg.py Adds async_sessionmaker[AsyncSession] annotation to main.
ddss/dump.ts Changes main to require Sequelize (aligned with centralized DB init).
ddss/dump.py Adds async_sessionmaker[AsyncSession] annotation to main.
Comments suppressed due to low confidence (1)

ddss/main.ts:88

  • cli() is now async, but the import.meta.main block calls it without await. In Deno/ESM this can cause the program to exit before the async action finishes, and any rejections become unhandled. Consider using await cli() (top-level await is supported) and switching to program.parseAsync(...) so Commander waits for the async .action handler.
export async function cli(): Promise<void> {
    const program = new Command();

    program
        .name("ddss")
        .description("DDSS - Distributed Deductive System Sorts: Run DDSS with an interactive deductive environment.")
        .option("-a, --addr <url>", "Database address URL. If not provided, uses a temporary SQLite database.")
        .option("-c, --component <names...>", "Components to run.", ["input", "output", "search", "egg"])
        .action(async (options) => {
            let addr = options.addr;
            let tmpDir: string | undefined;
            if (!addr) {
                tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "ddss-"));
                const dbPath = path.join(tmpDir, "ddss.db");
                addr = `sqlite:///${dbPath}`;
            }
            console.log(`addr: ${addr}`);

            if (addr.startsWith("sqlite://")) {
                addr = addr.replace("sqlite:///", "sqlite:");
            } else if (addr.startsWith("mysql://")) {
                // Nothing to change
            } else if (addr.startsWith("mariadb://")) {
                // Nothing to change
            } else if (addr.startsWith("postgresql://")) {
                addr = addr.replace("postgresql://", "postgres://");
            } else {
                console.error(`error: unsupported database: ${addr}`);
                return;
            }

            await run(addr, options.component);

            if (tmpDir) {
                await fs.rm(tmpDir, { recursive: true, force: true });
            }
        });

    program.parse();
}

if (import.meta.main) {
    cli();
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread ddss/load.ts
Comment on lines 21 to 26
const ds = parse(data);
const dsStr = ds.toString();

await insertOrIgnore(Fact, dsStr);
const idea = strRuleGetStrIdea(dsStr);
await insertOrIgnore(Fact, ds);
const idea = strRuleGetStrIdea(ds);
if (idea) {
await insertOrIgnore(Idea, idea);

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse() returns a non-string value here, but insertOrIgnore expects data: string and strRuleGetStrIdea expects data: string. Passing ds directly will fail type-checking (and likely store [object Object] at runtime). Convert ds to a string before inserting/deriving the idea (e.g., use ds.toString() consistently as in other modules).

Copilot uses AI. Check for mistakes.
Comment thread ddss/input.ts
Comment on lines 23 to 28
const ds = parse(data);
const dsStr = ds.toString();

await insertOrIgnore(Fact, dsStr);
const idea = strRuleGetStrIdea(dsStr);
await insertOrIgnore(Fact, ds);
const idea = strRuleGetStrIdea(ds);
if (idea) {
await insertOrIgnore(Idea, idea);

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in load.ts: insertOrIgnore and strRuleGetStrIdea both take string, but this code passes the parse() result directly. Convert the parsed value to a string (e.g., ds.toString()) before inserting/extracting the idea.

Copilot uses AI. Check for mistakes.
Comment thread ddss/main.ts
Comment on lines +25 to 33
async function run(addr: string, components: string[]): Promise<void> {
const sequelize = await initializeDatabase(addr);

for (const name of components) {
if (!(name in componentMap)) {
console.error(`error: unsupported component: ${name}`);
return;
}
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializeDatabase(addr) is executed before validating components. If an unsupported component is provided, run() returns early without closing the Sequelize connection, leaking resources and possibly leaving a temp DB file locked. Validate components before initializing the database, or ensure sequelize.close() runs on all early-return paths (e.g., via try/finally).

Copilot uses AI. Check for mistakes.
Comment thread ddss/main.py
Comment on lines +15 to 18
component_map: dict[str, callable[[async_sessionmaker[AsyncSession]], Awaitable[None]]] = {
"search": search,
"egg": egg,
"input": input,

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type annotation uses callable[...], but callable is a built-in function, not a typing construct. This will fail type checking. Use typing.Callable[[async_sessionmaker[AsyncSession]], Awaitable[None]] (and import Callable) for component_map’s value type.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ts有一些不一致的,python是认真写的,但ts是生成的,比如input那里有一个多余的toString

2 participants