diff --git a/.publishrc b/.publishrc index 7d39c002..5bb40572 100644 --- a/.publishrc +++ b/.publishrc @@ -14,6 +14,6 @@ "confirm": true, "publishCommand": "npm publish", "publishTag": "latest", - "prePublishScript": "npm test", + "prePublishScript": "npm test && npm test-types", "postPublishScript": false } \ No newline at end of file diff --git a/package.json b/package.json index 2ed0e05b..df0f3102 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "./src/fxp.js", "scripts": { "test": "nyc --reporter=lcov --reporter=text jasmine spec/*spec.js", + "test-types": "tsc --noEmit spec/typings/typings-test.ts", "unit": "jasmine", "coverage": "nyc report --reporter html --reporter text -t .nyc_output --report-dir .nyc_output/summary", "perf": "node ./benchmark/perfTest3.js", @@ -46,6 +47,7 @@ "@babel/plugin-transform-runtime": "^7.13.10", "@babel/preset-env": "^7.13.10", "@babel/register": "^7.13.8", + "@types/node": "20", "babel-loader": "^8.2.2", "cytorus": "^0.2.9", "eslint": "^8.3.0", @@ -54,6 +56,7 @@ "nyc": "^15.1.0", "prettier": "^1.19.1", "publish-please": "^5.5.2", + "typescript": "5", "webpack": "^5.64.4", "webpack-cli": "^4.9.1" }, diff --git a/spec/typings/typings-test.ts b/spec/typings/typings-test.ts new file mode 100644 index 00000000..3d35951f --- /dev/null +++ b/spec/typings/typings-test.ts @@ -0,0 +1,47 @@ +import { + XMLParser, + XMLBuilder, + XMLValidator, + type X2jOptions, + type XmlBuilderOptions, + type validationOptions, +} from '../../src/fxp'; + +const parseOpts: X2jOptions = {}; + +const XML = ` + + + + +`; + +const parser = new XMLParser(parseOpts); +const parsed = parser.parse(XML); + +console.log(!!parsed); + +const buildOpts: XmlBuilderOptions = {}; + +const builder = new XMLBuilder(buildOpts); + +const built = builder.build({ + any_name: { + person: { + phone: [ + 15555551313, + 15555551212 + ] + } + } +}); + +console.log(!!built); + +const validateOpts: validationOptions = {}; + +const isValid = XMLValidator.validate(built, validateOpts); + +console.log(!!isValid); + + diff --git a/src/fxp.d.ts b/src/fxp.d.ts index d622f27e..ada4502a 100644 --- a/src/fxp.d.ts +++ b/src/fxp.d.ts @@ -1,81 +1,375 @@ type X2jOptions = { - preserveOrder: boolean; - attributeNamePrefix: string; - attributesGroupName: false | string; - textNodeName: string; - ignoreAttributes: boolean; - removeNSPrefix: boolean; - allowBooleanAttributes: boolean; - parseTagValue: boolean; - parseAttributeValue: boolean; - trimValues: boolean; - cdataPropName: false | string; - commentPropName: false | string; - /** -Control how tag value should be parsed. Called only if tag value is not empty - -@returns {undefined|null} `undefined` or `null` to set original value. -@returns {unknown} -1. Different value or value with different data type to set new value.
-2. Same value to set parsed value if `parseTagValue: true`. - */ - tagValueProcessor: (tagName: string, tagValue: string, jPath: string, hasAttributes: boolean, isLeafNode: boolean) => unknown; - attributeValueProcessor: (attrName: string, attrValue: string, jPath: string) => unknown; - numberParseOptions: strnumOptions; - stopNodes: string[]; - unpairedTags: string[]; - alwaysCreateTextNode: boolean; - isArray: (tagName: string, jPath: string, isLeafNode: boolean, isAttribute: boolean) => boolean; - processEntities: boolean; - htmlEntities: boolean; - ignoreDeclaration: boolean; - ignorePiTags: boolean; - transformTagName: ((tagName: string) => string) | false; - transformAttributeName: ((attributeName: string) => string) | false; - /** -Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned. -Modify `attrs` object to control attributes for the given tag. - -@returns {string} new tag name. -@returns false to skip the tag - */ - updateTag: (tagName: string, jPath: string, attrs: {[k: string]: string}) => string | boolean; + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when parsing + * + * Defaults to `true` + */ + ignoreAttributes?: boolean; + + /** + * Whether to remove namespace string from tag and attribute names + * + * Defaults to `false` + */ + removeNSPrefix?: boolean; + + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * Whether to parse tag value with `strnum` package + * + * Defaults to `true` + */ + parseTagValue?: boolean; + + /** + * Whether to parse tag value with `strnum` package + * + * Defaults to `false` + */ + parseAttributeValue?: boolean; + + /** + * Whether to remove surrounding whitespace from tag or attribute value + * + * Defaults to `true` + */ + trimValues?: boolean; + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (tagName: string, tagValue: string, jPath: string, hasAttributes: boolean, isLeafNode: boolean) => unknown; + + /** + * Control how attribute value should be parsed + * + * @param attrName + * @param attrValue + * @param jPath + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPath) => val` + */ + attributeValueProcessor?: (attrName: string, attrValue: string, jPath: string) => unknown; + + /** + * Options to pass to `strnum` for parsing numbers + * + * Defaults to `{ hex: true, leadingZeros: true, eNotation: true }` + */ + numberParseOptions?: strnumOptions; + + /** + * Nodes to stop parsing at + * + * Defaults to `[]` + */ + stopNodes?: string[]; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Whether to always create a text node + * + * Defaults to `false` + */ + alwaysCreateTextNode?: boolean; + + /** + * Determine whether a tag should be parsed as an array + * + * @param tagName + * @param jPath + * @param isLeafNode + * @param isAttribute + * @returns {boolean} + * + * Defaults to `() => false` + */ + isArray?: (tagName: string, jPath: string, isLeafNode: boolean, isAttribute: boolean) => boolean; + + /** + * Whether to process default and DOCTYPE entities + * + * Defaults to `true` + */ + processEntities?: boolean; + + /** + * Whether to process HTML entities + * + * Defaults to `false` + */ + htmlEntities?: boolean; + + /** + * Whether to ignore the declaration tag from output + * + * Defaults to `false` + */ + ignoreDeclaration?: boolean; + + /** + * Whether to ignore Pi tags + * + * Defaults to `false` + */ + ignorePiTags?: boolean; + + /** + * Transform tag names + * + * Defaults to `false` + */ + transformTagName?: ((tagName: string) => string) | false; + + /** + * Transform attribute names + * + * Defaults to `false` + */ + transformAttributeName?: ((attributeName: string) => string) | false; + + /** + * Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned. + * Modify `attrs` object to control attributes for the given tag. + * + * @returns {string} new tag name. + * @returns false to skip the tag + * + * Defaults to `(tagName, jPath, attrs) => tagName` + */ + updateTag?: (tagName: string, jPath: string, attrs: {[k: string]: string}) => string | boolean; }; + type strnumOptions = { hex: boolean; leadingZeros: boolean, skipLike?: RegExp, eNotation?: boolean } -type X2jOptionsOptional = Partial; + type validationOptions = { - allowBooleanAttributes: boolean; - unpairedTags: string[]; + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; }; -type validationOptionsOptional = Partial; type XmlBuilderOptions = { - attributeNamePrefix: string; - attributesGroupName: false | string; - textNodeName: string; - ignoreAttributes: boolean; - cdataPropName: false | string; - commentPropName: false | string; - format: boolean; - indentBy: string; - arrayNodeName: string; - suppressEmptyNode: boolean; - suppressUnpairedNode: boolean; - suppressBooleanAttributes: boolean; - preserveOrder: boolean; - unpairedTags: string[]; - stopNodes: string[]; - tagValueProcessor: (name: string, value: unknown) => string; - attributeValueProcessor: (name: string, value: unknown) => string; - processEntities: boolean; - oneListGroup: boolean; + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when parsing + * + * Defaults to `true` + */ + ignoreAttributes?: boolean; + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Whether to make output pretty instead of single line + * + * Defaults to `false` + */ + format?: boolean; + + + /** + * If `format` is set to `true`, sets the indent string + * + * Defaults to ` ` + */ + indentBy?: string; + + /** + * Give a name to a top-level array + * + * Defaults to `undefined` + */ + arrayNodeName?: string; + + /** + * Create empty tags for tags with no text value + * + * Defaults to `false` + */ + suppressEmptyNode?: boolean; + + /** + * Suppress an unpaired tag + * + * Defaults to `true` + */ + suppressUnpairedNode?: boolean; + + /** + * Don't put a value for boolean attributes + * + * Defaults to `true` + */ + suppressBooleanAttributes?: boolean; + + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Nodes to stop parsing at + * + * Defaults to `[]` + */ + stopNodes?: string[]; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (name: string, value: unknown) => string; + + /** + * Control how attribute value should be parsed + * + * @param attrName + * @param attrValue + * @param jPath + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPath) => val` + */ + attributeValueProcessor?: (name: string, value: unknown) => string; + + /** + * Whether to process default and DOCTYPE entities + * + * Defaults to `true` + */ + processEntities?: boolean; + + + oneListGroup?: boolean; }; -type XmlBuilderOptionsOptional = Partial; type ESchema = string | object | Array; @@ -89,8 +383,8 @@ type ValidationError = { }; export class XMLParser { - constructor(options?: X2jOptionsOptional); - parse(xmlData: string | Buffer ,validationOptions?: validationOptionsOptional | boolean): any; + constructor(options?: X2jOptions); + parse(xmlData: string | Buffer ,validationOptions?: validationOptions | boolean): any; /** * Add Entity which is not by default supported by this library * @param entityIndentifier {string} Eg: 'ent' for &ent; @@ -100,9 +394,9 @@ export class XMLParser { } export class XMLValidator{ - static validate( xmlData: string, options?: validationOptionsOptional): true | ValidationError; + static validate( xmlData: string, options?: validationOptions): true | ValidationError; } export class XMLBuilder { - constructor(options?: XmlBuilderOptionsOptional); + constructor(options?: XmlBuilderOptions); build(jObj: any): any; }