Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ def runLint() {
'''
}

def runTypeCheck() {
sh label: 'run-type-check', script: '''
export PATH=${NODE_HOME_DIR}/bin:$PATH
cd node-client-api
npm ci
npm run test:types
'''
}

def runE2ETests() {
sh label: 'run-e2e-tests', script: '''
export PATH=${NODE_HOME_DIR}/bin:$PATH
Expand Down Expand Up @@ -130,6 +139,7 @@ pipeline {
steps {
runAuditReport()
runLint()
runTypeCheck()
runDockerCompose('ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-12')
runTests()
runE2ETests()
Expand Down
84 changes: 84 additions & 0 deletions marklogic.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
*/

// Type definitions for marklogic
// Project: https://github.com/marklogic/node-client-api
// Documentation: https://docs.marklogic.com/guide/node-dev

/**
* MarkLogic Node.js Client API
*
* IMPORTANT: This library uses CommonJS exports. Import patterns:
*
* For TypeScript/ES Modules:
* import marklogic from 'marklogic'; // Preferred
* const db = marklogic.createDatabaseClient({...});
*
* For CommonJS:
* const marklogic = require('marklogic');
* const db = marklogic.createDatabaseClient({...});
*/

declare module 'marklogic' {
/**
* Configuration object for creating a database client.
* Used by the createDatabaseClient function to establish connection parameters.
*/
export interface DatabaseClientConfig {
/** The host with the REST server for the database (defaults to 'localhost') */
host?: string;
/** The port with the REST server for the database (defaults to 8000) */
port?: number;
/** The user with permission to access the database */
user?: string;
/** The password for the user with permission to access the database */
password?: string;
/** The name of the database to access (defaults to the database for the REST server) */
database?: string;
/** The authentication type (defaults to 'digest') */
authType?: 'basic' | 'digest' | 'application-level' | 'certificate' | 'kerberos' | 'saml' | 'cloud';
/** Whether the REST server uses SSL (defaults to false) */
ssl?: boolean;
/** The trusted certificate(s), if required for SSL */
ca?: string | string[] | Buffer | Buffer[];
/** The public x509 certificate to use for SSL */
cert?: string | Buffer;
/** The private key to use for SSL */
key?: string | Buffer;
/** The public x509 certificate and private key as a single PKCS12 file to use for SSL */
pfx?: Buffer;
/** The passphrase for the PKCS12 file or private key */
passphrase?: string;
/** Whether to reject unauthorized SSL certificates (defaults to true) */
rejectUnauthorized?: boolean;
/** The SAML token to use for authentication with the REST server */
token?: string;
/** Connection pooling agent */
agent?: any;
/** API version to use */
apiVersion?: string;
}

/**
* A database client object returned by createDatabaseClient.
* Provides access to document, graph, and query operations.
*/
export interface DatabaseClient {
// Methods will be added as we expand the type definitions
// For now, this is a placeholder to enable basic typing
}

/**
* Creates a DatabaseClient object for accessing a database.
* @param config - Configuration for connecting to the database
* @returns A DatabaseClient object for performing database operations
*/
export function createDatabaseClient(config: DatabaseClientConfig): DatabaseClient;

const marklogic: {
createDatabaseClient: typeof createDatabaseClient;
};

export default marklogic;
}
32 changes: 24 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
"version": "4.0.1",
"license": "Apache-2.0",
"main": "./lib/marklogic.js",
"types": "marklogic.d.ts",
"files": [
"lib",
"marklogic.d.ts",
"README.md",
"NOTICE.txt",
"LICENSE.txt",
"CHANGELOG.txt"
],
"scripts": {
"doc": "jsdoc -c jsdoc.json lib/*.js README.md",
"lint": "gulp lint"
"lint": "gulp lint",
"test:types": "tsc --noEmit"
},
"keywords": [
"marklogic",
Expand Down Expand Up @@ -43,6 +53,7 @@
},
"devDependencies": {
"@jsdoc/salty": "0.2.9",
"@types/node": "22.10.1",
"ajv": "8.17.1",
"ast-types": "0.14.2",
"astring": "1.9.0",
Expand All @@ -60,7 +71,8 @@
"moment": "2.30.1",
"sanitize-html": "2.17.0",
"should": "13.2.3",
"stream-to-array": "2.3.0"
"stream-to-array": "2.3.0",
"typescript": "5.7.2"
},
"optionalDependencies": {
"kerberos": "^2.0.1",
Expand Down
76 changes: 76 additions & 0 deletions test-typescript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# TypeScript Type Definitions Testing

This directory contains TypeScript tests to verify that the type definitions in `marklogic.d.ts` work correctly.

## How to Test Types

Run the type checking with:

```bash
npm run test:types
```

This command runs `tsc --noEmit`, which checks for TypeScript errors without generating JavaScript files.

## What Gets Tested

### ✅ Type Constraints
- Valid values for `authType` (basic, digest, application-level, certificate, kerberos, saml, cloud)
- Optional vs required properties
- Union types (string | Buffer for certificates)
- Array types (string[] for multiple certificates)

### ✅ Type Safety
If you uncomment the error examples in the test files, TypeScript will catch:
- Invalid `authType` values
- Incorrect property types
- Missing required properties

## Test Files

### `type-constraints.test.ts`
Tests the `DatabaseClientConfig` interface constraints without importing the module. This works immediately without needing to simulate package installation.

### `basic-types.test.ts` (currently excluded)
Full integration test that imports the `marklogic` module. To use this:
1. Build/link the package locally (`npm link`)
2. Remove it from the exclude list in `tsconfig.json`
3. Run `npm run test:types` again

## Adding More Type Tests

As you add more interfaces to `marklogic.d.ts`, add corresponding test files here. The pattern is:

1. Create a `.test.ts` file
2. Write TypeScript code that uses the types
3. Include examples that should work AND commented examples that should fail
4. Run `npm run test:types` to verify

## Why This Approach?

TypeScript's compiler is the best way to test type definitions because:
- It catches type errors at compile time (before runtime)
- It validates type constraints (like union types for `authType`)
- It ensures IntelliSense and autocomplete will work for users
- It's fast and doesn't require running actual code

## Example: Testing for Type Errors

```typescript
// This should work fine ✅
const good: DatabaseClientConfig = {
authType: 'digest'
};

// This should fail ❌ (uncomment to test)
// const bad: DatabaseClientConfig = {
// authType: 'invalid-type'
// };
```

When you uncomment the error example and run `npm run test:types`, you'll see:
```
error TS2322: Type '"invalid-type"' is not assignable to type 'basic' | 'digest' | ...
```

This confirms your types are working correctly!
74 changes: 74 additions & 0 deletions test-typescript/basic-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
*/

// This file tests that TypeScript types work correctly
// Run with: npm run test:types
import marklogic from 'marklogic';

// Test 1: Valid configuration should compile without errors
const validConfig: marklogic.DatabaseClientConfig = {
host: 'localhost',
port: 8000,
user: 'admin',
password: 'admin',
authType: 'digest'
};

const db = marklogic.createDatabaseClient(validConfig);

// Test 2: Another valid configuration with SSL
const sslConfig: marklogic.DatabaseClientConfig = {
host: 'secure.marklogic.com',
port: 8443,
user: 'admin',
password: 'admin',
authType: 'basic',
ssl: true,
rejectUnauthorized: true
};

const secureDb = marklogic.createDatabaseClient(sslConfig);

// Test 3: This should cause a type error if uncommented (invalid authType)
// const invalidConfig: marklogic.DatabaseClientConfig = {
// host: 'localhost',
// authType: 'invalid-auth-type' // ERROR: not a valid authType
// };

// Test 4: Type inference should work (no explicit type annotation needed)
const inferredConfig = {
host: 'localhost',
port: 8000,
user: 'admin',
password: 'admin'
};
const db2 = marklogic.createDatabaseClient(inferredConfig);

// Test 5: Testing optional fields - this should compile fine
const minimalConfig: marklogic.DatabaseClientConfig = {
user: 'admin',
password: 'admin'
};

// Test 6: Testing all auth types (all should be valid)
const authTypes: Array<marklogic.DatabaseClientConfig['authType']> = [
'basic',
'digest',
'application-level',
'certificate',
'kerberos',
'saml',
'cloud'
];

// Test 7: Testing SSL certificate options
const certConfig: marklogic.DatabaseClientConfig = {
host: 'localhost',
ssl: true,
ca: Buffer.from('certificate'),
cert: 'string-cert',
key: Buffer.from('key')
};

console.log('✅ TypeScript types validated successfully!');
Loading
Loading