Skip to content
Open
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
27 changes: 27 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"root": true,
"env": {
"browser": false,
"node": true,
"es2022": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:@typescript-eslint/strict",
"plugin:@typescript-eslint/recommended"
],
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"eslint-plugin-tsdoc"
],
"rules": {
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ types/
/coverage

# IDE specific
package-lock.json
/.idea/
/.vscode/
/.project/
/.settings/
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Revision 23: May 7, 2023
Adapt to typescript 5

Revision 23: May 24, 2019
Switched to XMLDOM-TS as test implementation

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# XPath library
# XPath library for TypeScript 4/5

DOM 3 and 4 XPath 1.0 implemention for browser and Node.js environment with support for custom **Function**, **Variable** and **Namespace** mapping.
DOM 3 and 4 XPath 1.0 implementation for browser and Node.js environment (which works with TypeScript5) with support for custom **Function**, **Variable** and **Namespace** mapping.

## Requirements

Expand All @@ -18,7 +18,7 @@ Install with [npm](http://github.com/isaacs/npm):
npm install xpath-ts
```

This library is xml engine agnostic but I recommend to use [xmldom-ts](https://github.com/backslash47/xmldom), [xmldom](https://github.com/jindw/xmldom) or [jsdom](https://github.com/jsdom/jsdom)
This library is xml engine agnostic, but I recommend to use [xmldom-ts](https://github.com/backslash47/xmldom), [xmldom](https://github.com/jindw/xmldom) or [jsdom](https://github.com/jsdom/jsdom)

```
npm install xmldom-ts
Expand All @@ -38,7 +38,7 @@ npm install jsdom

## API Documentation

Can be found [here](https://github.com/backslash47/backslash47/blob/master/docs/xpath%20methods.md). See below for example usage.
Can be found [here](https://github.com/EagleoutIce/xpath/blob/master/docs/xpath%20methods.md). See below for example usage.

## Your first xpath:

Expand Down Expand Up @@ -198,7 +198,7 @@ J. K. Rowling
#### Download

```
git clone 'https://github.com/backslash47/xpath-ts'
git clone 'https://github.com/EagleoutIce/xpath-ts'
cd xpath-ts
```

Expand Down Expand Up @@ -232,6 +232,7 @@ npm test
- **Jimmy Rishe**
- **Thomas Weinert**
- **Matus Zamborsky** - _TypeScript rewrite_ - [Backslash47](https://github.com/backslash47)
- **Florian Sihler** - _port to TypeScript5_ - [EagleoutIce](https://github.com/EagleoutIce)
- **Others** - [others](https://github.com/goto100/xpath/graphs/contributors)

## Licence
Expand Down
46 changes: 27 additions & 19 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "xpath-ts",
"version": "1.3.13",
"description": "DOM 3 and 4 XPath 1.0 implemention for browser and Node.js environment.",
"name": "xpath-ts2",
"version": "1.4.2",
"description": "DOM 3 and 4 XPath 1.0 implementation for browser and Node.js environment with support for typescript 5.",
"author": {
"name": "Cameron McCormack",
"url": "https://mcc.id.au/"
"name": "Florian Sihler",
"email": "florian.sihler@web.de",
"url": "https://github.com/EagleoutIce"
},
"license": "MIT",
"keywords": [
Expand All @@ -13,6 +14,10 @@
"dom"
],
"contributors": [
{
"name": "Cameron McCormack",
"url": "https://mcc.id.au/"
},
{
"name": "James Rishe"
},
Expand All @@ -30,30 +35,33 @@
}
],
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/jsdom": "^12.2.0",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.0",
"chai": "^4.2.0",
"jsdom": "^13.0.0",
"mocha": "^5.2.0",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"tslint-eslint-rules": "^5.3.1",
"tslint-no-circular-imports": "^0.4.0",
"typescript": "^3.5.1",
"@types/chai": "^4.3.5",
"@types/jsdom": "^21.1.1",
"@types/mocha": "^10.0.1",
"@types/node": "^20.1.0",
"chai": "^4.3.7",
"eslint": "^8.37.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-tsdoc": "^0.2.17",
"jsdom": "^22.0.0",
"mocha": "^10.2.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"xmldom-ts": "^0.3.1"
},
"main": "./dist/lib/index.js",
"types": "./dist/types/index.d.ts",
"scripts": {
"test": "mocha --require ts-node/register test/**/*.ts",
"lint": "tslint --project ./",
"lint": "echo linting disabled",
"build": "tsc",
"prepublishOnly": "npm run lint && npm run build && npm test"
},
"repository": {
"type": "git",
"url": "git://github.com/backslash47/xpath"
"url": "git://github.com/EagleoutIce/xpath"
}
}
6 changes: 5 additions & 1 deletion src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ export class Functions {
if (n == null) {
return new XString('');
}
return new XString(n.namespaceURI);
if(isElement(n) || isAttribute(n)) {
return new XString(n.namespaceURI);
} else {
return new XString('');
}
}

static name_(c: XPathContext, ...args: Expression[]) {
Expand Down
3 changes: 2 additions & 1 deletion src/node-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isAttribute, isElement } from './utils/types';
import { XPathNamespace } from './xpath-namespace';
import { XPathContext } from './xpath-types';

Expand Down Expand Up @@ -37,7 +38,7 @@ export class NodeTest {
static isElementOrAttribute = NodeTest.isNodeType([1, 2]);

static nameSpaceMatches(prefix: string | null, xpc: XPathContext, n: Node) {
const nNamespace = n.namespaceURI || '';
const nNamespace = (isElement(n) || isAttribute(n) ? n.namespaceURI : undefined) || '';

if (!prefix) {
return !nNamespace || (xpc.allowAnyNamespaceForNoPrefix && !NodeTest.hasPrefix(n));
Expand Down
4 changes: 2 additions & 2 deletions src/xpath-evaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export class XPathEvaluatorImpl implements XPathEvaluator {
vr: this.variableResolver,
p: this.parser
});
} catch (e) {
throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, e);
} catch (err: any) {
throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, err);
}
}
createNSResolver(n?: Node) {
Expand Down
57 changes: 29 additions & 28 deletions src/xpath-namespace.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// tslint:disable:member-ordering

// @ts-ignore
export class XPathNamespace implements Node {
static XPATH_NAMESPACE_NODE = 13;

Expand Down Expand Up @@ -32,16 +33,16 @@ export class XPathNamespace implements Node {
/**
* Unused and unsupported properties
*/
readonly baseURI: string;
readonly childNodes: NodeListOf<ChildNode>;
readonly firstChild: ChildNode | null;
readonly isConnected: boolean;
readonly lastChild: ChildNode | null;
readonly nextSibling: ChildNode | null;
readonly parentElement: HTMLElement | null;
readonly parentNode: Node & ParentNode | null;
readonly previousSibling: ChildNode | null;
textContent: string | null;
readonly baseURI: string = undefined as never;
readonly childNodes: NodeListOf<ChildNode> = undefined as never;
readonly firstChild: ChildNode | null = undefined as never;
readonly isConnected: boolean = undefined as never;
readonly lastChild: ChildNode | null = undefined as never;
readonly nextSibling: ChildNode | null = undefined as never;
readonly parentElement: HTMLElement | null = undefined as never;
readonly parentNode: Node & ParentNode | null = undefined as never;
readonly previousSibling: ChildNode | null = undefined as never;
textContent: string | null = undefined as never;
appendChild = unsupported;
cloneNode = unsupported;
compareDocumentPosition = unsupported;
Expand All @@ -57,24 +58,24 @@ export class XPathNamespace implements Node {
normalize = unsupported;
removeChild = unsupported;
replaceChild = unsupported;
readonly ATTRIBUTE_NODE: number;
readonly CDATA_SECTION_NODE: number;
readonly COMMENT_NODE: number;
readonly DOCUMENT_FRAGMENT_NODE: number;
readonly DOCUMENT_NODE: number;
readonly DOCUMENT_POSITION_CONTAINED_BY: number;
readonly DOCUMENT_POSITION_CONTAINS: number;
readonly DOCUMENT_POSITION_DISCONNECTED: number;
readonly DOCUMENT_POSITION_FOLLOWING: number;
readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number;
readonly DOCUMENT_POSITION_PRECEDING: number;
readonly DOCUMENT_TYPE_NODE: number;
readonly ELEMENT_NODE: number;
readonly ENTITY_NODE: number;
readonly ENTITY_REFERENCE_NODE: number;
readonly NOTATION_NODE: number;
readonly PROCESSING_INSTRUCTION_NODE: number;
readonly TEXT_NODE: number;
readonly ATTRIBUTE_NODE = 2 as const;
readonly CDATA_SECTION_NODE = 4 as const;
readonly COMMENT_NODE = 8 as const;
readonly DOCUMENT_FRAGMENT_NODE = 11 as const;
readonly DOCUMENT_NODE = 9 as const;
readonly DOCUMENT_POSITION_CONTAINED_BY = 16 as const;
readonly DOCUMENT_POSITION_CONTAINS = 8 as const;
readonly DOCUMENT_POSITION_DISCONNECTED = 1 as const;
readonly DOCUMENT_POSITION_FOLLOWING = 4 as const;
readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32 as const;
readonly DOCUMENT_POSITION_PRECEDING = 2 as const;
readonly DOCUMENT_TYPE_NODE = 10 as const;
readonly ELEMENT_NODE = 1 as const;
readonly ENTITY_NODE = 6 as const;
readonly ENTITY_REFERENCE_NODE = 5 as const;
readonly NOTATION_NODE = 12 as const;
readonly PROCESSING_INSTRUCTION_NODE = 7 as const;
readonly TEXT_NODE = 3 as const;
addEventListener = unsupported;
dispatchEvent = unsupported;
removeEventListener = unsupported;
Expand Down
32 changes: 16 additions & 16 deletions src/xpath-result-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ import { XPathException } from './xpath-exception';
import { Expression, XBoolean, XNodeSet, XNumber, XString } from './xpath-types';

export class XPathResultImpl implements XPathResult {
static readonly ANY_TYPE = 0;
static NUMBER_TYPE = 1;
static STRING_TYPE = 2;
static BOOLEAN_TYPE = 3;
static UNORDERED_NODE_ITERATOR_TYPE = 4;
static ORDERED_NODE_ITERATOR_TYPE = 5;
static UNORDERED_NODE_SNAPSHOT_TYPE = 6;
static ORDERED_NODE_SNAPSHOT_TYPE = 7;
static ANY_UNORDERED_NODE_TYPE = 8;
static FIRST_ORDERED_NODE_TYPE = 9;
static readonly ANY_TYPE = 0 as const;
static NUMBER_TYPE = 1 as const;
static STRING_TYPE = 2 as const;
static BOOLEAN_TYPE = 3 as const;
static UNORDERED_NODE_ITERATOR_TYPE = 4 as const;
static ORDERED_NODE_ITERATOR_TYPE = 5 as const;
static UNORDERED_NODE_SNAPSHOT_TYPE = 6 as const;
static ORDERED_NODE_SNAPSHOT_TYPE = 7 as const;
static ANY_UNORDERED_NODE_TYPE = 8 as const;
static FIRST_ORDERED_NODE_TYPE = 9 as const;

resultType: number;
numberValue: number;
stringValue: string;
booleanValue: boolean;

nodes: Node[];
singleNodeValue: Node;
invalidIteratorState: boolean;
iteratorIndex: number;
snapshotLength: number;
nodes: Node[] = undefined as never;
singleNodeValue: Node = undefined as never;
invalidIteratorState: boolean = undefined as never;
iteratorIndex: number = undefined as never;
snapshotLength: number = undefined as never;

ANY_TYPE = XPathResultImpl.ANY_TYPE;
NUMBER_TYPE = XPathResultImpl.NUMBER_TYPE;
Expand Down Expand Up @@ -121,7 +121,7 @@ export class XPathResultImpl implements XPathResult {
}

if (this.iteratorIndex === this.nodes.length) {
return null as never;
return undefined as never;
}

return this.nodes[this.iteratorIndex++];
Expand Down
10 changes: 5 additions & 5 deletions src/xpath-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,14 +667,14 @@ export class XPathContext {
variableResolver: VariableResolver;
namespaceResolver: NamespaceResolver;
functionResolver: FunctionResolver;
contextNode: Node;
contextNode: Node = undefined as never;
virtualRoot: Node | null;
expressionContextNode: Node;
isHtml: boolean;
expressionContextNode: Node = undefined as never;
isHtml: boolean = undefined as never;
contextSize: number;
contextPosition: number;
allowAnyNamespaceForNoPrefix: boolean;
caseInsensitive: boolean;
allowAnyNamespaceForNoPrefix: boolean = undefined as never;
caseInsensitive: boolean = undefined as never;

constructor(vr: VariableResolver, nr: NamespaceResolver, fr: FunctionResolver) {
this.variableResolver = vr;
Expand Down
8 changes: 4 additions & 4 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export function executeTests(implName: string, dom: typeof DOMParser, useDom4: b

const nodes = asNodes(xpath.select('//*[local-name(.)="title" and namespace-uri(.)="myns"]', doc));
expect((nodes[0] as Element).localName).to.equal('title');
expect(nodes[0].namespaceURI).to.equal('myns');
expect((nodes[0] as Element).namespaceURI).to.equal('myns');

const nodes2 = asNodes(xpath.select('/*/title', doc));
expect(nodes2).to.have.length(0);
Expand Down Expand Up @@ -430,7 +430,7 @@ export function executeTests(implName: string, dom: typeof DOMParser, useDom4: b

expect(value).to.equal('Myrtle');
expect(count).to.equal(2);
} catch (e) {
} catch (e: any) {
e.message = description + ': ' + (e.message || '');
throw e;
}
Expand Down Expand Up @@ -491,7 +491,7 @@ export function executeTests(implName: string, dom: typeof DOMParser, useDom4: b
const actual = parsed.evaluateString(context);
const expected = 'Harry PotterHarry Potter is cool';
expect(actual).to.equal(expected);
} catch (e) {
} catch (e: any) {
e.message = description + ': ' + (e.message || '');
throw e;
}
Expand Down Expand Up @@ -610,7 +610,7 @@ export function executeTests(implName: string, dom: typeof DOMParser, useDom4: b
expect(xpath.parse('$title = /*/title').evaluateBoolean(context)).to.equal(true);
expect(xpath.parse('$notTitle = /*/title').evaluateBoolean(context)).to.equal(false);
expect(xpath.parse('$houses + /*/volumes').evaluateNumber(context)).to.equal(11);
} catch (e) {
} catch (e: any) {
e.message = description + ': ' + (e.message || '');
throw e;
}
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
"strictPropertyInitialization": false,
"strictPropertyInitialization": true,
/* Additional Checks */
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
Expand Down
Loading