Some checks failed
		
		
	
	Types tests / Test (lts/*) (push) Has been cancelled
				
			Lint / Lint (lts/*) (push) Has been cancelled
				
			CodeQL / Analyze (javascript) (push) Has been cancelled
				
			CI / Test (20) (push) Has been cancelled
				
			CI / Test (22) (push) Has been cancelled
				
			CI / Test (24) (push) Has been cancelled
				
			
		
			
				
	
	
		
			1542 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1542 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Copyright 2020 Mozilla Foundation
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
import {
 | 
						|
  $dump,
 | 
						|
  $getChildren,
 | 
						|
  $getChildrenByClass,
 | 
						|
  $getChildrenByName,
 | 
						|
  $text,
 | 
						|
} from "../../src/core/xfa/symbol_utils.js";
 | 
						|
import { Binder } from "../../src/core/xfa/bind.js";
 | 
						|
import { searchNode } from "../../src/core/xfa/som.js";
 | 
						|
import { XFAParser } from "../../src/core/xfa/parser.js";
 | 
						|
 | 
						|
describe("XFAParser", function () {
 | 
						|
  describe("Parse XFA", function () {
 | 
						|
    it("should parse a xfa document and create an object to represent it", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" uuid="1234" invalid="foo">
 | 
						|
  <config xmlns="http://www.xfa.org/schema/xci/3.1/">
 | 
						|
    <present>
 | 
						|
      <pdf name="hello">
 | 
						|
        <adobeExtensionLevel>
 | 
						|
          7
 | 
						|
        </adobeExtensionLevel>
 | 
						|
      </pdf>
 | 
						|
      <invalid><a>foobar</a></invalid>
 | 
						|
    </present>
 | 
						|
    <acrobat>
 | 
						|
      <submitUrl>http://a.b.c</submitUrl>
 | 
						|
      <acrobat7>
 | 
						|
        <dynamicRender>
 | 
						|
          forbidden
 | 
						|
        </dynamicRender>
 | 
						|
      </acrobat7>
 | 
						|
      <autoSave>enabled</autoSave>
 | 
						|
      <submitUrl>
 | 
						|
                 http://d.e.f
 | 
						|
      </submitUrl>
 | 
						|
      <submitUrl>http://g.h.i</submitUrl>
 | 
						|
      <validate>foobar</validate>
 | 
						|
    </acrobat>
 | 
						|
  </config>
 | 
						|
  <template baseProfile="full" xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <extras>
 | 
						|
      <float>1.23</float>
 | 
						|
      <boolean>1</boolean>
 | 
						|
      <integer>314</integer>
 | 
						|
      <float>2.71</float>
 | 
						|
    </extras>
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <area x="hello" y="-3.14in" relevant="-foo +bar" />
 | 
						|
        <color value="111, 222, 123" />
 | 
						|
        <color value="111, abc, 123" />
 | 
						|
        <medium imagingBBox="1,2in,3.4cm,5.67px" />
 | 
						|
        <medium imagingBBox="1,2in,-3cm,4px" />
 | 
						|
      </proto>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const attributes = {
 | 
						|
        id: "",
 | 
						|
        name: "",
 | 
						|
        use: "",
 | 
						|
        usehref: "",
 | 
						|
      };
 | 
						|
      const mediumAttributes = {
 | 
						|
        id: "",
 | 
						|
        long: 0,
 | 
						|
        orientation: "portrait",
 | 
						|
        short: 0,
 | 
						|
        stock: "",
 | 
						|
        trayIn: "auto",
 | 
						|
        trayOut: "auto",
 | 
						|
        use: "",
 | 
						|
        usehref: "",
 | 
						|
      };
 | 
						|
      const colorAttributes = {
 | 
						|
        cSpace: "SRGB",
 | 
						|
        id: "",
 | 
						|
        use: "",
 | 
						|
        usehref: "",
 | 
						|
      };
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const expected = {
 | 
						|
        uuid: "1234",
 | 
						|
        timeStamp: "",
 | 
						|
        template: {
 | 
						|
          baseProfile: "full",
 | 
						|
          extras: {
 | 
						|
            ...attributes,
 | 
						|
            float: [
 | 
						|
              { ...attributes, $content: 1.23 },
 | 
						|
              { ...attributes, $content: 2.71 },
 | 
						|
            ],
 | 
						|
            boolean: { ...attributes, $content: 1 },
 | 
						|
            integer: { ...attributes, $content: 314 },
 | 
						|
          },
 | 
						|
          subform: {
 | 
						|
            access: "open",
 | 
						|
            allowMacro: 0,
 | 
						|
            anchorType: "topLeft",
 | 
						|
            colSpan: 1,
 | 
						|
            columnWidths: [0],
 | 
						|
            h: "",
 | 
						|
            hAlign: "left",
 | 
						|
            id: "",
 | 
						|
            layout: "position",
 | 
						|
            locale: "",
 | 
						|
            maxH: 0,
 | 
						|
            maxW: 0,
 | 
						|
            mergeMode: "consumeData",
 | 
						|
            minH: 0,
 | 
						|
            minW: 0,
 | 
						|
            name: "",
 | 
						|
            presence: "visible",
 | 
						|
            relevant: [],
 | 
						|
            restoreState: "manual",
 | 
						|
            scope: "name",
 | 
						|
            use: "",
 | 
						|
            usehref: "",
 | 
						|
            w: "",
 | 
						|
            x: 0,
 | 
						|
            y: 0,
 | 
						|
            proto: {
 | 
						|
              area: {
 | 
						|
                ...attributes,
 | 
						|
                colSpan: 1,
 | 
						|
                x: 0,
 | 
						|
                y: -226.08,
 | 
						|
                relevant: [
 | 
						|
                  { excluded: true, viewname: "foo" },
 | 
						|
                  { excluded: false, viewname: "bar" },
 | 
						|
                ],
 | 
						|
              },
 | 
						|
              color: [
 | 
						|
                {
 | 
						|
                  ...colorAttributes,
 | 
						|
                  value: { r: 111, g: 222, b: 123 },
 | 
						|
                },
 | 
						|
                {
 | 
						|
                  ...colorAttributes,
 | 
						|
                  value: { r: 111, g: 0, b: 123 },
 | 
						|
                },
 | 
						|
              ],
 | 
						|
              medium: [
 | 
						|
                {
 | 
						|
                  ...mediumAttributes,
 | 
						|
                  imagingBBox: {
 | 
						|
                    x: 1,
 | 
						|
                    y: 144,
 | 
						|
                    width: 96.3779527559055,
 | 
						|
                    height: 5.67,
 | 
						|
                  },
 | 
						|
                },
 | 
						|
                {
 | 
						|
                  ...mediumAttributes,
 | 
						|
                  imagingBBox: {
 | 
						|
                    x: -1,
 | 
						|
                    y: -1,
 | 
						|
                    width: -1,
 | 
						|
                    height: -1,
 | 
						|
                  },
 | 
						|
                },
 | 
						|
              ],
 | 
						|
            },
 | 
						|
          },
 | 
						|
        },
 | 
						|
        config: {
 | 
						|
          acrobat: {
 | 
						|
            acrobat7: {
 | 
						|
              dynamicRender: {
 | 
						|
                $content: "forbidden",
 | 
						|
              },
 | 
						|
            },
 | 
						|
            autoSave: {
 | 
						|
              $content: "enabled",
 | 
						|
            },
 | 
						|
            validate: {
 | 
						|
              $content: "preSubmit",
 | 
						|
            },
 | 
						|
            submitUrl: [
 | 
						|
              {
 | 
						|
                $content: "http://a.b.c",
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $content: "http://d.e.f",
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $content: "http://g.h.i",
 | 
						|
              },
 | 
						|
            ],
 | 
						|
          },
 | 
						|
          present: {
 | 
						|
            pdf: {
 | 
						|
              name: "hello",
 | 
						|
              adobeExtensionLevel: {
 | 
						|
                $content: 7,
 | 
						|
              },
 | 
						|
            },
 | 
						|
          },
 | 
						|
        },
 | 
						|
      };
 | 
						|
      expect(root[$dump]()).toEqual(expected);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and check namespaces", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <config xmlns:foo="http:/www.foo.com" xmlns="http://www.xfa.org/schema/xci/3.1/">
 | 
						|
    <present xmlns="http://www.mozilla.org">
 | 
						|
      <pdf name="hello">
 | 
						|
        <adobeExtensionLevel>
 | 
						|
          7
 | 
						|
        </adobeExtensionLevel>
 | 
						|
      </pdf>
 | 
						|
    </present>
 | 
						|
    <acrobat>
 | 
						|
      <foo:submitUrl>http://a.b.c</foo:submitUrl>
 | 
						|
      <submitUrl>http://c.b.a</submitUrl>
 | 
						|
    </acrobat>
 | 
						|
  </config>
 | 
						|
  <template baseProfile="full" xmlns="http://www.allizom.org">
 | 
						|
    <extras>
 | 
						|
      <float>1.23</float>
 | 
						|
    </extras>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const expected = {
 | 
						|
        uuid: "",
 | 
						|
        timeStamp: "",
 | 
						|
        config: {
 | 
						|
          acrobat: {
 | 
						|
            submitUrl: { $content: "http://c.b.a" },
 | 
						|
          },
 | 
						|
        },
 | 
						|
      };
 | 
						|
      expect(root[$dump]()).toEqual(expected);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and parse CDATA when needed", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <field>
 | 
						|
        <extras>
 | 
						|
          <exData contentType="text/html" name="foo">
 | 
						|
            <![CDATA[<body xmlns="http://www.w3.org/1999/xhtml">
 | 
						|
              <span>hello</span></body>]]>
 | 
						|
          </exData>
 | 
						|
        </extra>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const exdata = searchNode(root, root, "foo")[0];
 | 
						|
      const body = exdata[$dump]().$content[$dump]();
 | 
						|
      const expected = {
 | 
						|
        $name: "body",
 | 
						|
        attributes: {},
 | 
						|
        children: [
 | 
						|
          { $content: "hello", $name: "span", attributes: {}, children: [] },
 | 
						|
        ],
 | 
						|
      };
 | 
						|
 | 
						|
      expect(body).toEqual(expected);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and apply some prototypes", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <font id="id1" typeface="Foo" size="123pt" weight="bold" posture="italic">
 | 
						|
          <fill>
 | 
						|
            <color value="1,2,3"/>
 | 
						|
          </fill>
 | 
						|
        </font>
 | 
						|
      </proto>
 | 
						|
      <field>
 | 
						|
        <font use="#id1"/>
 | 
						|
      </field>
 | 
						|
      <field>
 | 
						|
        <font use="#id1" size="456pt" weight="bold" posture="normal">
 | 
						|
          <fill>
 | 
						|
            <color value="4,5,6"/>
 | 
						|
          </fill>
 | 
						|
          <extras id="id2"/>
 | 
						|
        </font>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      let font = root.template.subform.field[0].font;
 | 
						|
      expect(font.typeface).toEqual("Foo");
 | 
						|
      expect(font.overline).toEqual(0);
 | 
						|
      expect(font.size).toEqual(123);
 | 
						|
      expect(font.weight).toEqual("bold");
 | 
						|
      expect(font.posture).toEqual("italic");
 | 
						|
      expect(font.fill.color.value).toEqual({ r: 1, g: 2, b: 3 });
 | 
						|
      expect(font.extras).toEqual(undefined);
 | 
						|
 | 
						|
      font = root.template.subform.field[1].font;
 | 
						|
      expect(font.typeface).toEqual("Foo");
 | 
						|
      expect(font.overline).toEqual(0);
 | 
						|
      expect(font.size).toEqual(456);
 | 
						|
      expect(font.weight).toEqual("bold");
 | 
						|
      expect(font.posture).toEqual("normal");
 | 
						|
      expect(font.fill.color.value).toEqual({ r: 4, g: 5, b: 6 });
 | 
						|
      expect(font.extras.id).toEqual("id2");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and apply some prototypes through usehref", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <draw name="foo">
 | 
						|
          <font typeface="Foo" size="123pt" weight="bold" posture="italic">
 | 
						|
            <fill>
 | 
						|
              <color value="1,2,3"/>
 | 
						|
            </fill>
 | 
						|
          </font>
 | 
						|
        </draw>
 | 
						|
      </proto>
 | 
						|
      <field>
 | 
						|
        <font usehref=".#som($template.#subform.foo.#font)"/>
 | 
						|
      </field>
 | 
						|
      <field>
 | 
						|
        <font usehref=".#som($template.#subform.foo.#font)" size="456pt" weight="bold" posture="normal">
 | 
						|
          <fill>
 | 
						|
            <color value="4,5,6"/>
 | 
						|
          </fill>
 | 
						|
          <extras id="id2"/>
 | 
						|
        </font>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      let font = root.template.subform.field[0].font;
 | 
						|
      expect(font.typeface).toEqual("Foo");
 | 
						|
      expect(font.overline).toEqual(0);
 | 
						|
      expect(font.size).toEqual(123);
 | 
						|
      expect(font.weight).toEqual("bold");
 | 
						|
      expect(font.posture).toEqual("italic");
 | 
						|
      expect(font.fill.color.value).toEqual({ r: 1, g: 2, b: 3 });
 | 
						|
      expect(font.extras).toEqual(undefined);
 | 
						|
 | 
						|
      font = root.template.subform.field[1].font;
 | 
						|
      expect(font.typeface).toEqual("Foo");
 | 
						|
      expect(font.overline).toEqual(0);
 | 
						|
      expect(font.size).toEqual(456);
 | 
						|
      expect(font.weight).toEqual("bold");
 | 
						|
      expect(font.posture).toEqual("normal");
 | 
						|
      expect(font.fill.color.value).toEqual({ r: 4, g: 5, b: 6 });
 | 
						|
      expect(font.extras.id).toEqual("id2");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document with xhtml", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <extras>
 | 
						|
      <text>
 | 
						|
        <body xmlns="http://www.w3.org/1999/xhtml">
 | 
						|
          <p style="foo: bar; text-indent:0.5in; line-height:11px;bar:foo;tab-stop: left 0.5in">
 | 
						|
            The first line of this paragraph is indented a half-inch.<br/>
 | 
						|
            Successive lines are not indented.<br/>
 | 
						|
            This is the last line of the paragraph.<br/>
 | 
						|
          </p>
 | 
						|
        </body>
 | 
						|
      </text>
 | 
						|
    </extras>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      const p = root.template.extras.text.$content[$getChildren]()[0];
 | 
						|
      expect(p.style).toEqual(
 | 
						|
        "text-indent:0.5in;line-height:11px;tab-stop:left 0.5in"
 | 
						|
      );
 | 
						|
      expect(p[$text]()).toEqual(
 | 
						|
        [
 | 
						|
          " The first line of this paragraph is indented a half-inch.\n",
 | 
						|
          " Successive lines are not indented.\n",
 | 
						|
          " This is the last line of the paragraph.\n ",
 | 
						|
        ].join("")
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and apply some prototypes with cycle", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <subform id="id1">
 | 
						|
          <subform use="#id1"/>
 | 
						|
        </subform>
 | 
						|
      </proto>
 | 
						|
    </subform>
 | 
						|
    <subform use="#id1"/>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      const subform = root.template.subform[1];
 | 
						|
 | 
						|
      expect(subform.id).toEqual("id1");
 | 
						|
      expect(subform.subform.id).toEqual("id1");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and apply some nested prototypes", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <color id="RED" value="7, 8, 9"/>
 | 
						|
        <font id="HELV" typeface="helvetica" size="31pt" weight="normal" posture="italic"> </font>
 | 
						|
        <font id="HELV-RED" use="#HELV">
 | 
						|
          <fill>
 | 
						|
            <color use="#RED"/>
 | 
						|
          </fill>
 | 
						|
        </font>
 | 
						|
      </proto>
 | 
						|
      <field>
 | 
						|
        <font use="#HELV-RED"/>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      const font = root.template.subform.field.font;
 | 
						|
 | 
						|
      expect(font.typeface).toEqual("helvetica");
 | 
						|
      expect(font.overline).toEqual(0);
 | 
						|
      expect(font.size).toEqual(31);
 | 
						|
      expect(font.weight).toEqual("normal");
 | 
						|
      expect(font.posture).toEqual("italic");
 | 
						|
      expect(font.fill.color.value).toEqual({ r: 7, g: 8, b: 9 });
 | 
						|
    });
 | 
						|
 | 
						|
    it("should parse a xfa document and apply a prototype with content", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform>
 | 
						|
      <proto>
 | 
						|
        <text id="TEXT">default TEXT</text>
 | 
						|
      </proto>
 | 
						|
      <field>
 | 
						|
        <value>
 | 
						|
          <text use="#TEXT"></text>
 | 
						|
        </value>
 | 
						|
      </field>
 | 
						|
      <field>
 | 
						|
        <value>
 | 
						|
          <text use="#TEXT">Overriding text</text>
 | 
						|
        </value>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml)[$dump]();
 | 
						|
      let field = root.template.subform.field[0];
 | 
						|
      expect(field.value.text.$content).toEqual("default TEXT");
 | 
						|
 | 
						|
      field = root.template.subform.field[1];
 | 
						|
      expect(field.value.text.$content).toEqual("Overriding text");
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe("Search in XFA", function () {
 | 
						|
    it("should search some nodes in a template object", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
    <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
      <subform name="Receipt" id="l">
 | 
						|
        <subform id="m">
 | 
						|
          <field name="Description" id="a">  </field>
 | 
						|
          <field name="Units" id="b">  </field>
 | 
						|
          <field name="Unit_Price" id="c">  </field>
 | 
						|
          <field name="Total_Price" id="d">  </field>
 | 
						|
        </subform>
 | 
						|
        <subform id="n">
 | 
						|
          <field name="Description" id="e">  </field>
 | 
						|
          <field name="Units" id="f">  </field>
 | 
						|
          <field name="Unit_Price" id="g">  </field>
 | 
						|
          <field name="Total_Price" id="h">  </field>
 | 
						|
        </subform>
 | 
						|
        <subform name="foo" id="o">
 | 
						|
          <field name="Description" id="p">  </field>
 | 
						|
          <field name="Units" id="q">  </field>
 | 
						|
          <field name="Unit_Price" id="r">  </field>
 | 
						|
          <field name="Total_Price" id="s">  </field>
 | 
						|
        </subform>
 | 
						|
        <field name="Sub_Total" id="i">  </field>
 | 
						|
        <field name="Tax" id="j">  </field>
 | 
						|
        <field name="Total_Price" id="k">  </field>
 | 
						|
      </subform>
 | 
						|
    </template>
 | 
						|
</xdp:xdp>
 | 
						|
        `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
 | 
						|
      let found = root[$getChildrenByName]("subform", true);
 | 
						|
      expect(found.map(x => x.id)).toEqual(["l", "m", "n", "o"]);
 | 
						|
 | 
						|
      found = root[$getChildrenByName]("Total_Price", true);
 | 
						|
      expect(found.map(x => x.id)).toEqual(["d", "h", "s", "k"]);
 | 
						|
 | 
						|
      found = root.template[$getChildrenByName]("Receipt", false);
 | 
						|
      const receipt = found[0];
 | 
						|
 | 
						|
      found = receipt[$getChildrenByName]("Total_Price", false);
 | 
						|
      expect(found.map(x => x.id)).toEqual(["d", "h", "k"]);
 | 
						|
 | 
						|
      expect(receipt[$getChildrenByClass]("name")).toEqual("Receipt");
 | 
						|
      const subforms = receipt[$getChildrenByClass]("subform");
 | 
						|
      expect(subforms.children.map(x => x.id)).toEqual(["m", "n", "o"]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should search some nodes in a template object using SOM", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
    <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
      <subform name="Receipt" id="l">
 | 
						|
        <subform id="m">
 | 
						|
          <field name="Description" id="a">  </field>
 | 
						|
          <field name="Units" id="b">  </field>
 | 
						|
          <field name="Unit_Price" id="c">  </field>
 | 
						|
          <field name="Total_Price" id="d">  </field>
 | 
						|
        </subform>
 | 
						|
        <subform id="n">
 | 
						|
          <field name="Description" id="e">  </field>
 | 
						|
          <field name="Units" id="f">  </field>
 | 
						|
          <field name="Unit_Price" id="g">  </field>
 | 
						|
          <field name="Total_Price" id="h">  </field>
 | 
						|
        </subform>
 | 
						|
        <subform name="foo" id="o">
 | 
						|
          <field name="Description" id="p">  </field>
 | 
						|
          <field name="Units" id="q">  </field>
 | 
						|
          <field name="Unit_Price" id="r">  </field>
 | 
						|
          <field name="Total_Price" id="s">  </field>
 | 
						|
        </subform>
 | 
						|
        <field name="Sub_Total" id="i">  </field>
 | 
						|
        <field name="Tax" id="j">  </field>
 | 
						|
        <field name="Total_Price" id="k">  </field>
 | 
						|
      </subform>
 | 
						|
    </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template..Description.id")[0][$text]()
 | 
						|
      ).toBe("a");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template..Description.id")[0][$text]()
 | 
						|
      ).toBe("a");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template..Description[0].id")[0][$text]()
 | 
						|
      ).toBe("a");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template..Description[1].id")[0][$text]()
 | 
						|
      ).toBe("e");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template..Description[2].id")[0][$text]()
 | 
						|
      ).toBe("p");
 | 
						|
      expect(searchNode(root, null, "$template.Receipt.id")[0][$text]()).toBe(
 | 
						|
        "l"
 | 
						|
      );
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template.Receipt.Description[1].id")[0][
 | 
						|
          $text
 | 
						|
        ]()
 | 
						|
      ).toBe("e");
 | 
						|
      expect(searchNode(root, null, "$template.Receipt.Description[2]")).toBe(
 | 
						|
        null
 | 
						|
      );
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template.Receipt.foo.Description.id")[0][
 | 
						|
          $text
 | 
						|
        ]()
 | 
						|
      ).toBe("p");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template.#subform.Sub_Total.id")[0][$text]()
 | 
						|
      ).toBe("i");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template.#subform.Units.id")[0][$text]()
 | 
						|
      ).toBe("b");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$template.#subform.Units.parent.id")[0][$text]()
 | 
						|
      ).toBe("m");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should search some nodes in a datasets object", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <Receipt>
 | 
						|
        <Page>1</Page>
 | 
						|
        <Detail PartNo="GS001">
 | 
						|
          <Description>Giant Slingshot</Description>
 | 
						|
          <Units>1</Units>
 | 
						|
          <Unit_Price>250.00</Unit_Price>
 | 
						|
          <Total_Price>250.00</Total_Price>
 | 
						|
        </Detail>
 | 
						|
        <Page>2</Page>
 | 
						|
        <Detail PartNo="RRB-LB">
 | 
						|
          <Description>Road Runner Bait, large bag</Description>
 | 
						|
          <Units>5</Units>
 | 
						|
          <Unit_Price>12.00</Unit_Price>
 | 
						|
          <Total_Price>60.00</Total_Price>
 | 
						|
        </Detail>
 | 
						|
        <Sub_Total>310.00</Sub_Total>
 | 
						|
        <Tax>24.80</Tax>
 | 
						|
        <Total_Price>334.80</Total_Price>
 | 
						|
      </Receipt>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const data = root.datasets.data;
 | 
						|
 | 
						|
      let found = data[$getChildrenByName]("Description", true);
 | 
						|
      expect(found.map(x => x[$text]())).toEqual([
 | 
						|
        "Giant Slingshot",
 | 
						|
        "Road Runner Bait, large bag",
 | 
						|
      ]);
 | 
						|
 | 
						|
      found = data[$getChildrenByName]("Total_Price", true);
 | 
						|
      expect(found.map(x => x[$text]())).toEqual(["250.00", "60.00", "334.80"]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should search some nodes using SOM from a non-root node", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <Receipt>
 | 
						|
        <Page>1</Page>
 | 
						|
        <Detail PartNo="GS001">
 | 
						|
          <Description>Giant Slingshot</Description>
 | 
						|
          <Units>1</Units>
 | 
						|
          <Unit_Price>250.00</Unit_Price>
 | 
						|
          <Total_Price>250.00</Total_Price>
 | 
						|
        </Detail>
 | 
						|
        <Page>2</Page>
 | 
						|
        <Detail PartNo="RRB-LB">
 | 
						|
          <Description>Road Runner Bait, large bag</Description>
 | 
						|
          <Units>5</Units>
 | 
						|
          <Unit_Price>12.00</Unit_Price>
 | 
						|
          <Total_Price>60.00</Total_Price>
 | 
						|
        </Detail>
 | 
						|
        <Sub_Total>310.00</Sub_Total>
 | 
						|
        <Tax>24.80</Tax>
 | 
						|
        <Total_Price>334.80</Total_Price>
 | 
						|
      </Receipt>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const [receipt] = root.datasets.data[$getChildren]("Receipt");
 | 
						|
      expect(
 | 
						|
        searchNode(root, receipt, "Detail[*].Total_Price").map(x => x[$text]())
 | 
						|
      ).toEqual(["250.00", "60.00"]);
 | 
						|
 | 
						|
      const [units] = searchNode(root, receipt, "Detail[1].Units");
 | 
						|
      expect(units[$text]()).toBe("5");
 | 
						|
 | 
						|
      let [found] = searchNode(root, units, "Total_Price");
 | 
						|
      expect(found[$text]()).toBe("60.00");
 | 
						|
 | 
						|
      found = searchNode(root, units, "Total_Pric");
 | 
						|
      expect(found).toEqual(null);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should search some nodes in a datasets object using SOM", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <Receipt Detail="Acme">
 | 
						|
        <Detail>foo</Detail>
 | 
						|
        <Detail>bar</Detail>
 | 
						|
     </Receipt>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      expect(searchNode(root, null, "$data.Receipt.Detail")[0][$text]()).toBe(
 | 
						|
        "Acme"
 | 
						|
      );
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$data.Receipt.Detail[0]")[0][$text]()
 | 
						|
      ).toBe("Acme");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$data.Receipt.Detail[1]")[0][$text]()
 | 
						|
      ).toBe("foo");
 | 
						|
      expect(
 | 
						|
        searchNode(root, null, "$data.Receipt.Detail[2]")[0][$text]()
 | 
						|
      ).toBe("bar");
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe("Bind data into form", function () {
 | 
						|
    it("should make a basic binding", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="A">
 | 
						|
      <subform name="B">
 | 
						|
        <field name="C">
 | 
						|
        </field>
 | 
						|
        <field name="D">
 | 
						|
        </field>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <A>
 | 
						|
        <C>xyz</C>
 | 
						|
      </A>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "A.B.C.value.text")[0][$dump]().$content
 | 
						|
      ).toBe("xyz");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make a basic binding and create a non-existing node", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="A" mergeMode="matchTemplate">
 | 
						|
      <subform name="B">
 | 
						|
        <field name="C">
 | 
						|
        </field>
 | 
						|
        <field name="D">
 | 
						|
          <value>
 | 
						|
            <text>foobar</text>
 | 
						|
          </value>
 | 
						|
        </field>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <A>
 | 
						|
      </A>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const binder = new Binder(root);
 | 
						|
      const form = binder.bind();
 | 
						|
      const data = binder.getData();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "A.B.D.value.text")[0][$dump]().$content
 | 
						|
      ).toBe("foobar");
 | 
						|
 | 
						|
      const expected = {
 | 
						|
        $name: "A",
 | 
						|
        attributes: {},
 | 
						|
        children: [
 | 
						|
          {
 | 
						|
            $name: "B",
 | 
						|
            attributes: {},
 | 
						|
            children: [
 | 
						|
              {
 | 
						|
                $name: "C",
 | 
						|
                attributes: {},
 | 
						|
                children: [],
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $name: "D",
 | 
						|
                attributes: {},
 | 
						|
                children: [],
 | 
						|
              },
 | 
						|
            ],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      };
 | 
						|
 | 
						|
      expect(searchNode(data, data, "A")[0][$dump]()).toEqual(expected);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make a basic binding and create a non-existing node with namespaceId equal to -1", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="A">
 | 
						|
      <subform name="B">
 | 
						|
        <field name="C">
 | 
						|
        </field>
 | 
						|
        <field name="D">
 | 
						|
          <value>
 | 
						|
            <text>foobar</text>
 | 
						|
          </value>
 | 
						|
        </field>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const binder = new Binder(root);
 | 
						|
      const form = binder.bind();
 | 
						|
      const data = binder.getData();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "A.B.D.value.text")[0][$dump]().$content
 | 
						|
      ).toBe("foobar");
 | 
						|
 | 
						|
      // Created nodes mustn't belong to xfa:datasets namespace.
 | 
						|
      const expected = {
 | 
						|
        $name: "A",
 | 
						|
        $ns: -1,
 | 
						|
        attributes: {},
 | 
						|
        children: [
 | 
						|
          {
 | 
						|
            $name: "B",
 | 
						|
            $ns: -1,
 | 
						|
            attributes: {},
 | 
						|
            children: [
 | 
						|
              {
 | 
						|
                $name: "C",
 | 
						|
                $ns: -1,
 | 
						|
                attributes: {},
 | 
						|
                children: [],
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $name: "D",
 | 
						|
                $ns: -1,
 | 
						|
                attributes: {},
 | 
						|
                children: [],
 | 
						|
              },
 | 
						|
            ],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      };
 | 
						|
 | 
						|
      expect(searchNode(data, data, "A")[0][$dump](/* hasNS */ true)).toEqual(
 | 
						|
        expected
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make another basic binding", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="registration">
 | 
						|
      <field name="first"> </field>
 | 
						|
      <field name="last">  </field>
 | 
						|
      <field name="apt">  </field>
 | 
						|
      <field name="street">  </field>
 | 
						|
      <field name="city">  </field>
 | 
						|
      <field name="country">  </field>
 | 
						|
      <field name="postalcode"/>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <registration>
 | 
						|
        <first>Jack</first>
 | 
						|
        <last>Spratt</last>
 | 
						|
        <apt/>
 | 
						|
        <street>99 Candlestick Lane</street>
 | 
						|
        <city>London</city>
 | 
						|
        <country>UK</country>
 | 
						|
        <postalcode>SW1</postalcode>
 | 
						|
      </registration>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.first..text")[0][$dump]().$content
 | 
						|
      ).toBe("Jack");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.last..text")[0][$dump]().$content
 | 
						|
      ).toBe("Spratt");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.apt..text")[0][$dump]().$content
 | 
						|
      ).toBe(undefined);
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.street..text")[0][$dump]().$content
 | 
						|
      ).toBe("99 Candlestick Lane");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.city..text")[0][$dump]().$content
 | 
						|
      ).toBe("London");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.country..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("UK");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration.postalcode..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("SW1");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make basic binding with extra subform", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="registration">
 | 
						|
      <field name="first"> </field>
 | 
						|
      <field name="last">  </field>
 | 
						|
      <subform name="address">
 | 
						|
        <field name="apt">  </field>
 | 
						|
        <field name="street">  </field>
 | 
						|
        <field name="city">  </field>
 | 
						|
        <field name="country">  </field>
 | 
						|
        <field name="postalcode">  </field>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <registration>
 | 
						|
        <first>Jack</first>
 | 
						|
        <last>Spratt</last>
 | 
						|
        <apt/>
 | 
						|
        <street>99 Candlestick Lane</street>
 | 
						|
        <city>London</city>
 | 
						|
        <country>UK</country>
 | 
						|
        <postalcode>SW1</postalcode>
 | 
						|
      </registration>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..first..text")[0][$dump]().$content
 | 
						|
      ).toBe("Jack");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..last..text")[0][$dump]().$content
 | 
						|
      ).toBe("Spratt");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..apt..text")[0][$dump]().$content
 | 
						|
      ).toBe(undefined);
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..street..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("99 Candlestick Lane");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..city..text")[0][$dump]().$content
 | 
						|
      ).toBe("London");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..country..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("UK");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..postalcode..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("SW1");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make basic binding with extra subform (consumeData)", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="registration" mergeMode="consumeData">
 | 
						|
      <subform name="address">
 | 
						|
        <field name="first"/>
 | 
						|
        <field name="last"/>
 | 
						|
        <field name="apt"/>
 | 
						|
        <field name="street"/>
 | 
						|
        <field name="city"/>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <registration>
 | 
						|
        <first>Jack</first>
 | 
						|
        <last>Spratt</last>
 | 
						|
        <address>
 | 
						|
          <apt>7</apt>
 | 
						|
          <street>99 Candlestick Lane</street>
 | 
						|
          <city>London</city>
 | 
						|
        </address>
 | 
						|
      </registration>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..first..text")[0][$dump]().$content
 | 
						|
      ).toBe("Jack");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..last..text")[0][$dump]().$content
 | 
						|
      ).toBe("Spratt");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..apt..text")[0][$dump]().$content
 | 
						|
      ).toBe("7");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..street..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("99 Candlestick Lane");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "registration..city..text")[0][$dump]().$content
 | 
						|
      ).toBe("London");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make basic binding with same names in different parts", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="application" mergeMode="consumeData">
 | 
						|
      <subform name="sponsor">
 | 
						|
        <field name="lastname">  </field>
 | 
						|
        <!-- sponsor's last name -->
 | 
						|
      </subform>
 | 
						|
      <field name="lastname">  </field>
 | 
						|
      <!-- applicant's last name -->
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <application>
 | 
						|
        <lastname>Abott</lastname>
 | 
						|
        <sponsor>
 | 
						|
          <lastname>Costello</lastname>
 | 
						|
        </sponsor>
 | 
						|
      </application>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "application.sponsor.lastname..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("Costello");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "application.lastname..text")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("Abott");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding and create nodes in data", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="root" mergeMode="matchTemplate">
 | 
						|
      <subform name="A">
 | 
						|
        <field name="a"/>
 | 
						|
        <field name="b"/>
 | 
						|
        <subform name="B">
 | 
						|
          <field name="c"/>
 | 
						|
          <field name="d"/>
 | 
						|
          <subform name="C">
 | 
						|
            <field name="e"/>
 | 
						|
            <field name="f"/>
 | 
						|
          </subform>
 | 
						|
        </subform>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <root>
 | 
						|
        <A>
 | 
						|
          <b>1</b>
 | 
						|
        </A>
 | 
						|
      </root>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const binder = new Binder(root);
 | 
						|
      const form = binder.bind();
 | 
						|
      const data = binder.getData();
 | 
						|
 | 
						|
      expect(searchNode(form, form, "root..b..text")[0][$dump]().$content).toBe(
 | 
						|
        "1"
 | 
						|
      );
 | 
						|
      expect(searchNode(data, data, "root.A.a")[0][$dump]().$name).toBe("a");
 | 
						|
      expect(searchNode(data, data, "root.A.B.c")[0][$dump]().$name).toBe("c");
 | 
						|
      expect(searchNode(data, data, "root.A.B.d")[0][$dump]().$name).toBe("d");
 | 
						|
      expect(searchNode(data, data, "root.A.B.C.e")[0][$dump]().$name).toBe(
 | 
						|
        "e"
 | 
						|
      );
 | 
						|
      expect(searchNode(data, data, "root.A.B.C.f")[0][$dump]().$name).toBe(
 | 
						|
        "f"
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding and set properties", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="Id">
 | 
						|
      <field name="LastName">
 | 
						|
        <setProperty ref="$data.Main.Style.NameFont" target="font.typeface"/>
 | 
						|
        <setProperty ref="$data.Main.Style.NameSize" target="font.size"/>
 | 
						|
        <setProperty ref="$data.Main.Help.LastName" target="assist.toolTip"/>
 | 
						|
        <font></font>
 | 
						|
        <assist>
 | 
						|
          <toolTip>
 | 
						|
          </toolTip>
 | 
						|
        </assist>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <Id>
 | 
						|
        <LastName>foo</LastName>
 | 
						|
      </Id>
 | 
						|
      <Main>
 | 
						|
        <Style>
 | 
						|
          <NameFont>myfont</NameFont>
 | 
						|
          <NameSize>123.4pt</NameSize>
 | 
						|
        </Style>
 | 
						|
        <Help>
 | 
						|
          <LastName>Give the name!</LastName>
 | 
						|
        </Help>
 | 
						|
      </Main>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "Id.LastName..text")[0][$dump]().$content
 | 
						|
      ).toBe("foo");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "Id.LastName.font.typeface")[0][$text]()
 | 
						|
      ).toBe("myfont");
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "Id.LastName.font.size")[0][$text]()
 | 
						|
      ).toEqual(123.4);
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "Id.LastName.assist.toolTip")[0][$dump]()
 | 
						|
          .$content
 | 
						|
      ).toBe("Give the name!");
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding and bind items", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="main">
 | 
						|
      <field name="CardName">
 | 
						|
        <bindItems ref="$data.main.ccs.cc[*]" labelRef="uiname" valueRef="token"/>
 | 
						|
        <ui>
 | 
						|
          <choiceList/>
 | 
						|
        </ui>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <main>
 | 
						|
        <ccs>
 | 
						|
          <cc uiname="Visa" token="VISA"/>
 | 
						|
          <cc uiname="Mastercard" token="MC"/>
 | 
						|
          <cc uiname="American Express" token="AMEX"/>
 | 
						|
        </ccs>
 | 
						|
        <CardName>MC</CardName>
 | 
						|
      </main>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "subform.CardName.items[*].text[*]").map(x =>
 | 
						|
          x[$text]()
 | 
						|
        )
 | 
						|
      ).toEqual([
 | 
						|
        "Visa",
 | 
						|
        "Mastercard",
 | 
						|
        "American Express",
 | 
						|
        "VISA",
 | 
						|
        "MC",
 | 
						|
        "AMEX",
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding and bind items with a ref", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="main">
 | 
						|
      <field name="CardName">
 | 
						|
        <bind match="dataRef" ref="$data.main.value"/>
 | 
						|
        <bindItems ref="$data.main.ccs.cc[*]" labelRef="uiname" valueRef="token"/>
 | 
						|
        <ui>
 | 
						|
          <choiceList/>
 | 
						|
        </ui>
 | 
						|
      </field>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <main>
 | 
						|
        <value>VISA</value>
 | 
						|
        <ccs>
 | 
						|
          <cc uiname="Visa" token="VISA"/>
 | 
						|
          <cc uiname="Mastercard" token="MC"/>
 | 
						|
          <cc uiname="American Express" token="AMEX"/>
 | 
						|
        </ccs>
 | 
						|
        <CardName>MC</CardName>
 | 
						|
      </main>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "subform.CardName.value.text").map(x =>
 | 
						|
          x[$text]()
 | 
						|
        )
 | 
						|
      ).toEqual(["VISA"]);
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "subform.CardName.items[*].text[*]").map(x =>
 | 
						|
          x[$text]()
 | 
						|
        )
 | 
						|
      ).toEqual([
 | 
						|
        "Visa",
 | 
						|
        "Mastercard",
 | 
						|
        "American Express",
 | 
						|
        "VISA",
 | 
						|
        "MC",
 | 
						|
        "AMEX",
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding with occurrences in consumeData mode", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="root" mergeMode="consumeData">
 | 
						|
      <subform name="section" id="section1">
 | 
						|
        <occur min="0" max="-1"/>
 | 
						|
        <bind match="dataRef" ref="$.section[*]"/>
 | 
						|
        <field name="line-item"/>
 | 
						|
      </subform>
 | 
						|
      <subform name="section" id="section2">
 | 
						|
        <occur min="0" max="-1"/>
 | 
						|
        <bind match="dataRef" ref="$.section[*]"/>
 | 
						|
        <field name="line-item"/>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <root>
 | 
						|
        <section>
 | 
						|
          <line-item>item1</line-item>
 | 
						|
        </section>
 | 
						|
        <section>
 | 
						|
          <line-item>item2</line-item>
 | 
						|
        </section>
 | 
						|
      </root>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "root.section[*].id").map(x => x[$text]())
 | 
						|
      ).toEqual(["section1", "section1"]);
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "root.section[*].line-item..text").map(x =>
 | 
						|
          x[$text]()
 | 
						|
        )
 | 
						|
      ).toEqual(["item1", "item2"]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding with occurrences in matchTemplate mode", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="root" mergeMode="matchTemplate">
 | 
						|
      <subform name="section" id="section1">
 | 
						|
        <occur min="0" max="-1"/>
 | 
						|
        <bind match="dataRef" ref="$.section[*]"/>
 | 
						|
        <field name="line-item"/>
 | 
						|
      </subform>
 | 
						|
      <subform name="section" id="section2">
 | 
						|
        <occur min="0" max="-1"/>
 | 
						|
        <bind match="dataRef" ref="$.section[*]"/>
 | 
						|
        <field name="line-item"/>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <root>
 | 
						|
        <section>
 | 
						|
          <line-item>item1</line-item>
 | 
						|
        </section>
 | 
						|
        <section>
 | 
						|
          <line-item>item2</line-item>
 | 
						|
        </section>
 | 
						|
      </root>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "root.section[*].id").map(x => x[$text]())
 | 
						|
      ).toEqual(["section1", "section1", "section2", "section2"]);
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "root.section[*].line-item..text").map(x =>
 | 
						|
          x[$text]()
 | 
						|
        )
 | 
						|
      ).toEqual(["item1", "item2", "item1", "item2"]);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make binding and create nodes in data with some bind tag", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="root" mergeMode="matchTemplate">
 | 
						|
      <subform name="A">
 | 
						|
        <occur max="-1"/>
 | 
						|
        <bind ref="$.root.foo[*]" match="dataRef"/>
 | 
						|
      </subform>
 | 
						|
      <subform name="B">
 | 
						|
        <occur max="2"/>
 | 
						|
        <bind ref="$.root.bar[2]" match="dataRef"/>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <root>
 | 
						|
      </root>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const binder = new Binder(root);
 | 
						|
      binder.bind();
 | 
						|
      const data = binder.getData();
 | 
						|
 | 
						|
      const expected = {
 | 
						|
        $name: "root",
 | 
						|
        children: [
 | 
						|
          {
 | 
						|
            $name: "root",
 | 
						|
            children: [
 | 
						|
              {
 | 
						|
                $name: "foo",
 | 
						|
                children: [],
 | 
						|
                attributes: {},
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $name: "bar",
 | 
						|
                children: [],
 | 
						|
                attributes: {},
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $name: "bar",
 | 
						|
                children: [],
 | 
						|
                attributes: {},
 | 
						|
              },
 | 
						|
              {
 | 
						|
                $name: "bar",
 | 
						|
                children: [],
 | 
						|
                attributes: {},
 | 
						|
              },
 | 
						|
            ],
 | 
						|
            attributes: {},
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        attributes: {},
 | 
						|
      };
 | 
						|
 | 
						|
      expect(searchNode(data, data, "root")[0][$dump]()).toEqual(expected);
 | 
						|
    });
 | 
						|
 | 
						|
    it("should make a binding with a bindItems", function () {
 | 
						|
      const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="A" mergeMode="matchTemplate">
 | 
						|
      <subform name="B">
 | 
						|
        <field name="C">
 | 
						|
          <ui>
 | 
						|
            <choicelist/>
 | 
						|
          </ui>
 | 
						|
          <bindItems ref="xfa.datasets.foo.bar[*]" labelRef="$" valueRef="oof"/>
 | 
						|
        </field>
 | 
						|
      </subform>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <foo>
 | 
						|
      <bar oof="a">1</bar>
 | 
						|
      <bar oof="b">2</bar>
 | 
						|
      <bar oof="c">3</bar>
 | 
						|
      <bar oof="d">4</bar>
 | 
						|
      <bar oof="e">5</bar>
 | 
						|
    </foo>
 | 
						|
    <xfa:data>
 | 
						|
      <A><B></B></A>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
      `;
 | 
						|
      const root = new XFAParser().parse(xml);
 | 
						|
      const form = new Binder(root).bind();
 | 
						|
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "A.B.C.items[0].text[*]").map(
 | 
						|
          x => x[$dump]().$content
 | 
						|
        )
 | 
						|
      ).toEqual(["1", "2", "3", "4", "5"]);
 | 
						|
      expect(
 | 
						|
        searchNode(form, form, "A.B.C.items[1].text[*]").map(
 | 
						|
          x => x[$dump]().$content
 | 
						|
        )
 | 
						|
      ).toEqual(["a", "b", "c", "d", "e"]);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  it("should make a binding with a element in an area", function () {
 | 
						|
    const xml = `
 | 
						|
<?xml version="1.0"?>
 | 
						|
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
 | 
						|
  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
 | 
						|
    <subform name="A" mergeMode="matchTemplate">
 | 
						|
      <area>
 | 
						|
        <field name="B"/>
 | 
						|
      </area>
 | 
						|
    </subform>
 | 
						|
  </template>
 | 
						|
  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
 | 
						|
    <xfa:data>
 | 
						|
      <A><B>foobar</B></A>
 | 
						|
    </xfa:data>
 | 
						|
  </xfa:datasets>
 | 
						|
</xdp:xdp>
 | 
						|
    `;
 | 
						|
    const root = new XFAParser().parse(xml);
 | 
						|
    const form = new Binder(root).bind();
 | 
						|
 | 
						|
    expect(searchNode(form, form, "A..B..text")[0][$dump]().$content).toBe(
 | 
						|
      "foobar"
 | 
						|
    );
 | 
						|
  });
 | 
						|
});
 |