diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e52c57f..c7ca9ccd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,7 @@ jobs: run: | npm ci npm run build + npm run validate-types:strict npm run test npm run test:integration - name: Lint diff --git a/.husky/pre-commit b/.husky/pre-commit index b39b28d2..16994bd1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -4,9 +4,12 @@ # Lint npm run lint:check; -# Test -npm test; +# Check typescript +npm run validate-types:strict # Build npm run build +# Test +npm test; + diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index abab7917..7c831cab 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,8 @@ +# TerminusDB Client v11.1.2 +## Fixes +* Adjust the release process to include version update task +* Fix typescript generation and add ci tests to prevent similar errors in the future. + # TerminusDB Client v11.1.1 ## Fixes * Update dependencies follow-redirects, webpack-dev-middleware, axios, braces, semver, micromatch, cross-spawn, word-wrap, on-headers, compression, form-data diff --git a/docs/release_process.md b/docs/release_process.md index 1f800a6d..c2aaeaf7 100644 --- a/docs/release_process.md +++ b/docs/release_process.md @@ -1,10 +1,10 @@ # Releasing a new version of the client -1. Review the changelog between last tagged release v10.0.34..HEAD -1. Create a branch and update RELEASE_NOTES.md based on changes -1. Add target version number to release notes -1. Check in and merge -1. Pick the latest version from the RELEASE_NOTES.md file -1. Update package.json version and run npm install -1. Tag the repo locally and push the tag, align the release (git tag -s v11.x.x) -1. The new release will be built and published 🎉 +1. Review the changelog between last tagged release v11.1.x..HEAD +2. Pick the next version number, update package.json, and run `npm install` +3. Create a branch and update RELEASE_NOTES.md based on changes +4. Add target version number to release notes +5. Check in and merge +6. Pick the latest version from the RELEASE_NOTES.md file +7. Copy the release notes in Markdown, create a tag on Github with the notes +8. The new release will be built and published 🎉 diff --git a/lib/typedef.js b/lib/typedef.js index 46227f4a..868413f9 100644 --- a/lib/typedef.js +++ b/lib/typedef.js @@ -187,7 +187,27 @@ const { ACTIONS } = Utils.ACTIONS; /** * @typedef {Object} NamedResourceData - { filename: "data.csv", data: "col1;col2\nval1;val2" } * @property {string} filename - Filename referenced in the WOQL query - * @property {string|Blob} data - Attached data, such as CSV contents + * @property {string|Blob|Buffer} data - Attached data, such as CSV contents + */ + +/** + * @typedef {Object} Frame - Represents a document frame, object frame, or property frame + * in the viewer system. Frames are used to describe the structure and properties of data + * being displayed or validated. + * @property {string} [subject] - Subject identifier + * @property {string} [property] - Property name + * @property {string} [type] - Type information (e.g., xsd:string, schema:Person) + * @property {*} [value] - Frame value + * @property {number} [depth] - Depth in frame hierarchy + * @property {string} [range] - Property range/type + * @property {string} [label] - Display label + * @property {Object} [parent] - Parent frame reference + * @property {Array} [children] - Child frames + * @property {string} [status] - Frame status: 'updated' | 'error' | 'new' | 'ok' + * @property {boolean} [literal] - Whether this represents a literal value + * @property {number} [index] - Index in parent collection + * @property {Object} [frame] - Nested frame data + * @property {string} [subjectClass] - Class of the subject */ module.exports = {}; diff --git a/lib/viewer/frameRule.js b/lib/viewer/frameRule.js index c4f2cb3d..bdd17990 100644 --- a/lib/viewer/frameRule.js +++ b/lib/viewer/frameRule.js @@ -8,6 +8,10 @@ /* eslint-disable no-use-before-define */ const TerminusRule = require('./terminusRule'); +/** + * @typedef {import('../typedef').Frame} Frame + */ + /** * @file Frame Rule * @license Apache Version 2 @@ -23,7 +27,7 @@ Object.setPrototypeOf(FrameRule.prototype, TerminusRule.TerminusRule.prototype); /** * Returns an array of rules that match the paased frame * @param {[FrameRule]} rules - array of rules to be tested - * @param {Frame} frame - object frame, property frame or data from to be tested + * @param {Frame | object} frame - document frame, object frame, or property frame to be tested * @param {function} [onmatch] - optional function to be called with args (frame, rule) * on each match */ diff --git a/lib/viewer/tableConfig.js b/lib/viewer/tableConfig.js index 6d67a401..7a98145c 100644 --- a/lib/viewer/tableConfig.js +++ b/lib/viewer/tableConfig.js @@ -124,8 +124,10 @@ WOQLTableConfig.prototype.prettyPrint = function () { }; /** - * @param {boolean} canfilter - * @returns WOQLTableConfig + * Gets or sets whether the table is filterable + * @param {boolean} [canfilter] - If provided, sets the filterable state + * @returns {boolean|WOQLTableConfig} - Returns the filterable state (boolean) when called + * without arguments, or returns this instance (WOQLTableConfig) for chaining when setting */ WOQLTableConfig.prototype.filterable = function (canfilter) { diff --git a/lib/viewer/terminusRule.js b/lib/viewer/terminusRule.js index da3a86f8..dec7ebb1 100644 --- a/lib/viewer/terminusRule.js +++ b/lib/viewer/terminusRule.js @@ -20,7 +20,7 @@ TerminusRule.prototype.literal = function (tf) { }; /** - * @param {[TYPE_URLS]} list - parameters are types identified by prefixed URLS (xsd:string...) + * @param {...string} list - parameters are types identified by prefixed URLS (xsd:string...) */ TerminusRule.prototype.type = function (...list) { if (typeof list === 'undefined' || list.length === 0) { diff --git a/lib/viewer/woqlChooser.js b/lib/viewer/woqlChooser.js index 6245c774..2d1ede29 100644 --- a/lib/viewer/woqlChooser.js +++ b/lib/viewer/woqlChooser.js @@ -6,6 +6,10 @@ const WOQLChooserConfig = require('./chooserConfig'); const UTILS = require('../utils'); const { WOQLRule } = require('./woqlRule'); +/** + * @typedef {import('../woqlClient')} WOQLClient + */ + /** * Very simple implementation of a WOQL backed chooser * Makes a drop down from a WOQL query - configuration tells it which columns to use... diff --git a/lib/viewer/woqlResult.js b/lib/viewer/woqlResult.js index c8bcec7c..ae0c1704 100644 --- a/lib/viewer/woqlResult.js +++ b/lib/viewer/woqlResult.js @@ -8,6 +8,11 @@ const UTILS = require('../utils'); const WOQL = require('../woql'); const WOQLQ = require('./woqlPaging'); + +/** + * @typedef {import('../query/woqlCore')} WOQLQuery + */ + /** * @module WOQLResult * @license Apache Version 2 diff --git a/lib/viewer/woqlStream.js b/lib/viewer/woqlStream.js index 8aaadb0d..71850c6e 100644 --- a/lib/viewer/woqlStream.js +++ b/lib/viewer/woqlStream.js @@ -1,5 +1,9 @@ const WOQLStreamConfig = require('./streamConfig'); +/** + * @typedef {import('../woqlClient')} WOQLClient + */ + /** * @param {WOQLClient} client * @param {WOQLStreamConfig} config diff --git a/lib/woql.js b/lib/woql.js index f709b613..329437c6 100644 --- a/lib/woql.js +++ b/lib/woql.js @@ -522,6 +522,9 @@ WOQL.evaluate = function (arithExp, resultVarName) { * @example * let [result] = vars("result") * eval(plus(2, minus(3, 1)), result) + * @deprecated Use {@link evaluate} instead. The name 'eval' conflicts with JavaScript's + * built-in eval in strict mode. + * @internal */ WOQL.eval = function (arithExp, resultVarName) { return new WOQLQuery().eval(arithExp, resultVarName); @@ -1350,7 +1353,7 @@ WOQL.iri = function (val) { /** * Generates javascript variables for use as WOQL variables within a query * @param {...string} varNames - * @returns {array} an array of javascript variables which can be dereferenced using the + * @returns {Array} an array of javascript variables which can be dereferenced using the * array destructuring operation * @example * const [a, b, c] = WOQL.vars("a", "b", "c") @@ -1364,7 +1367,7 @@ WOQL.vars = function (...varNames) { /** * Generates unique javascript variables for use as WOQL variables within a query * @param {...string} varNames - * @returns {array} an array of javascript variables which can be dereferenced using the + * @returns {Array} an array of javascript variables which can be dereferenced using the * array destructuring operation * @example * const [a, b, c] = WOQL.vars("a", "b", "c") diff --git a/lib/woqlClient.js b/lib/woqlClient.js index edd73a41..f6e23ec9 100644 --- a/lib/woqlClient.js +++ b/lib/woqlClient.js @@ -14,6 +14,10 @@ const ConnectionConfig = require('./connectionConfig'); const WOQL = require('./woql'); const WOQLQuery = require('./query/woqlCore'); +/** + * @typedef {import('./typedef').NamedResourceData} NamedResourceData + */ + /** * @license Apache Version 2 * @class diff --git a/package-lock.json b/package-lock.json index 36e21abd..6ea23293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@terminusdb/terminusdb-client", - "version": "11.1.1", + "version": "11.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@terminusdb/terminusdb-client", - "version": "11.1.1", + "version": "11.1.2", "license": "Apache-2.0", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index e24f2acf..f966819e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@terminusdb/terminusdb-client", - "version": "11.1.1", + "version": "11.1.2", "description": "TerminusDB client library", "main": "index.js", "types": "./dist/typescript/index.d.ts", @@ -71,14 +71,15 @@ "cover": "nyc --check-coverage --lines 30 npm run test:only ", "lint:check": "eslint .", "lint": "eslint --fix .", - "build": "webpack --mode production && tsc", + "validate-types:strict": "npm run generate-types && tsc --project tsconfig.validate.json", + "build": "webpack --mode production && npm run generate-types", "coveralls-after": "nyc --reporter=lcov mocha --require @babel/register --require @babel/preset-env", "npm:publish": "npm publish --access public", "test-single": "mocha $1", "woql-test": "mocha test/woqlTripleBuilder.spec.js test/woql.spec.js test/woqlTripleBuilder01.spec.js test/woqlExtra.spec.js", "git-tag": "git tag $npm_package_version", "prepare": "husky install", - "generate-types": "tsc" + "generate-types": "tsc && node scripts/fix-eval-export.js" }, "repository": { "type": "git", diff --git a/scripts/fix-eval-export.js b/scripts/fix-eval-export.js new file mode 100644 index 00000000..84334bcb --- /dev/null +++ b/scripts/fix-eval-export.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ + +/** + * Post-process generated .d.ts files to fix the 'eval' export issue. + * The function 'eval' is a reserved keyword in strict mode, so we rename it + * in the type definitions while keeping the JavaScript implementation for backward compatibility. + */ + +const fs = require('fs'); +const path = require('path'); + +const woqlDtsPath = path.join(__dirname, '../dist/typescript/lib/woql.d.ts'); + +if (!fs.existsSync(woqlDtsPath)) { + console.error(`Error: ${woqlDtsPath} not found. Run 'npm run generate-types' first.`); + process.exit(1); +} + +let content = fs.readFileSync(woqlDtsPath, 'utf8'); + +// Remove the eval export line (it's deprecated, use evaluate instead) +const evalExportRegex = /export declare function eval\([^)]*\): [^;]+;[\r\n]*/g; +const originalLength = content.length; + +content = content.replace(evalExportRegex, ''); + +if (content.length < originalLength) { + fs.writeFileSync(woqlDtsPath, content, 'utf8'); + console.log('>> Removed eval export from woql.d.ts (use evaluate() instead)'); +} else { + console.log('>> No eval export found in woql.d.ts, no workaround needed'); +} diff --git a/tsconfig.validate.json b/tsconfig.validate.json new file mode 100644 index 00000000..97de8df8 --- /dev/null +++ b/tsconfig.validate.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist/typescript/**/*.d.ts", "index.js"], + "compilerOptions": { + "allowJs": true, + "declaration": false, + "emitDeclarationOnly": false, + "noEmit": true, + "skipLibCheck": false, + "strict": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true + } +}