diff --git a/.editorconfig b/.editorconfig index 9b7352176a..46c1eafce3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ indent_style = space indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true +end_of_line = lf [*.md] max_line_length = off diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..c91cc33aeb --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: dolanmiu +patreon: dolanmiu +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml new file mode 100644 index 0000000000..a063d1ee1d --- /dev/null +++ b/.github/workflows/default.yml @@ -0,0 +1,104 @@ +name: Default +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + - name: Install Dependencies + run: npm ci + - name: Build + run: npm run build + - name: Archive Production Artifact + uses: actions/upload-artifact@master + with: + name: build + path: build + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + - name: Install Dependencies + run: npm ci + - name: Test + run: npm run test.coverage + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + - name: Install Dependencies + run: npm ci + - name: Lint + run: npm run lint + prettier: + name: Prettier + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + - name: Install Dependencies + run: npm ci + - name: Prettier + run: npm run style + demos: + name: Run Demos + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + - name: Install Dependencies + run: npm ci + - name: Download Artifact + uses: actions/download-artifact@master + with: + name: build + path: build + - name: Run demos + run: | + npm run ts-node -- ./demo/1-basic.ts + npm run ts-node -- ./demo/2-declaritive-styles.ts + npm run ts-node -- ./demo/3-numbering-and-bullet-points.ts + npm run ts-node -- ./demo/4-basic-table.ts + npm run ts-node -- ./demo/5-images.ts + npm run ts-node -- ./demo/6-page-borders.ts + npm run ts-node -- ./demo/7-landscape.ts + npm run ts-node -- ./demo/8-header-footer.ts + npm run ts-node -- ./demo/9-images-in-header-and-footer.ts + npm run ts-node -- ./demo/10-my-cv.ts + npm run ts-node -- ./demo/11-declaritive-styles-2.ts + npm run ts-node -- ./demo/12-scaling-images.ts + npm run ts-node -- ./demo/13-xml-styles.ts + npm run ts-node -- ./demo/14-page-numbers.ts + npm run ts-node -- ./demo/15-page-break-before.ts + npm run ts-node -- ./demo/16-multiple-sections.ts + npm run ts-node -- ./demo/17-footnotes.ts + npm run ts-node -- ./demo/18-image-from-buffer.ts + npm run ts-node -- ./demo/19-export-to-base64.ts + npm run ts-node -- ./demo/20-table-cell-borders.ts + npm run ts-node -- ./demo/21-bookmarks.ts + npm run ts-node -- ./demo/22-right-to-left-text.ts + npm run ts-node -- ./demo/23-base64-images.ts + npm run ts-node -- ./demo/24-images-to-table-cell.ts + npm run ts-node -- ./demo/26-paragraph-borders.ts + npm run ts-node -- ./demo/27-declaritive-styles-3.ts + npm run ts-node -- ./demo/28-table-of-contents.ts + npm run ts-node -- ./demo/29-numbered-lists.ts + npm run ts-node -- ./demo/30-template-document.ts + npm run ts-node -- ./demo/31-tables.ts + npm run ts-node -- ./demo/32-merge-and-shade-table-cells.ts + npm run ts-node -- ./demo/33-sequential-captions.ts + npm run ts-node -- ./demo/34-floating-tables.ts diff --git a/.gitignore b/.gitignore index 8a7c8baf67..7b65d85792 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,6 @@ docs/.nojekyll .idea # Lock files -package-lock.json yarn.lock # Documents diff --git a/.nvmrc b/.nvmrc index 469d080845..e338b86593 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v8 \ No newline at end of file +v10 diff --git a/.nycrc b/.nycrc index d5f12ccbc3..3a897e4c79 100644 --- a/.nycrc +++ b/.nycrc @@ -1,14 +1,15 @@ { "check-coverage": true, - "lines": 92.35, - "functions": 88.28, - "branches": 84.64, - "statements": 92.16, + "lines": 97.77, + "functions": 93.89, + "branches": 94.83, + "statements": 97.75, "include": [ "src/**/*.ts" ], "exclude": [ - "src/**/*.spec.ts" + "src/**/*.spec.ts", + "src/import-dotx/import-dotx.ts" ], "reporter": [ "lcov", diff --git a/.travis.yml b/.travis.yml index 3bf1b47690..3d4166c482 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - 9 + - 10 install: - npm install - npm install -g codecov @@ -10,7 +10,7 @@ script: - npm run style - npm run build - npm run ts-node -- ./demo/1-basic.ts - - npm run e2e "My Document.docx" +# - npm run e2e "My Document.docx" - npm run ts-node -- ./demo/2-declaritive-styles.ts - npm run ts-node -- ./demo/3-numbering-and-bullet-points.ts - npm run ts-node -- ./demo/4-basic-table.ts @@ -20,7 +20,7 @@ script: - npm run ts-node -- ./demo/8-header-footer.ts - npm run ts-node -- ./demo/9-images-in-header-and-footer.ts - npm run ts-node -- ./demo/10-my-cv.ts - - npm run e2e "My Document.docx" +# - npm run e2e "My Document.docx" - npm run ts-node -- ./demo/11-declaritive-styles-2.ts - npm run ts-node -- ./demo/12-scaling-images.ts - npm run ts-node -- ./demo/13-xml-styles.ts diff --git a/README.md b/README.md index 7cb5c93879..1df764e12c 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![NPM version][npm-image]][npm-url] [![Downloads per month][downloads-image]][downloads-url] [![Build Status][travis-image]][travis-url] +[![GitHub Action Workflow Status][github-actions-workflow-image]][github-actions-workflow-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Known Vulnerabilities][snky-image]][snky-url] [![Chat on Gitter][gitter-image]][gitter-url] @@ -18,7 +19,7 @@ [![codecov][codecov-image]][codecov-url]

- drawing + drawing

# Demo @@ -27,13 +28,22 @@ Here are examples of `docx` being used with basic `HTML/JS` in a browser environment: -* https://codepen.io/anon/pen/dqoVgQ -* https://jsfiddle.net/3xhezb5w/2 +* https://codepen.io/dolanmiu/pen/RwNeObg +* https://jsfiddle.net/dolanmiu/kqxrj35u/1/ Here is an example of `docx` working in `Angular`: * https://stackblitz.com/edit/angular-afvxtz +Here is an example of `docx` working in `React`: + +* https://stackblitz.com/edit/react-ts-qq25sp +* https://stackblitz.com/edit/react-ts-qdqu7z (adding images to Word Document) + +Here is an example of `docx` working in `Vue.js`: + +* https://stackblitz.com/edit/vuejs-docx + ## Node Press `endpoint` on the `RunKit` website: @@ -50,7 +60,7 @@ Press `endpoint` on the `RunKit` website: * https://runkit.com/dolanmiu/docx-demo8 - Header and Footer * https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx** -More [here](https://docx.js.org/#/examples) and [here](https://github.com/dolanmiu/docx/tree/master/demo) +More [here](https://github.com/dolanmiu/docx/tree/master/demo) # How to use & Documentation @@ -58,7 +68,7 @@ Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/ # Examples -Check the `examples` section in the [documentation](https://docx.js.org/#/examples) and the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples. +Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples. # Contributing @@ -73,6 +83,12 @@ Read the contribution guidelines [here](https://docx.js.org/#/contribution-guide [drawing](https://www.dabblewriter.com/) [drawing](https://turbopatent.com/) [drawing](http://www.madisoncres.com/) +[drawing](https://www.beekast.com/) +[drawing](https://herraizsoto.com/) +[drawing](http://www.ativer.com.br/) +[drawing](https://www.arity.co/) +[drawing](https://www.circadianrisk.com/) + ...and many more! @@ -89,6 +105,8 @@ Made with 💖 [downloads-url]: https://npmjs.org/package/docx [travis-image]: https://travis-ci.org/dolanmiu/docx.svg?branch=master [travis-url]: https://travis-ci.org/dolanmiu/docx +[github-actions-workflow-image]: https://github.com/dolanmiu/docx/workflows/Default/badge.svg +[github-actions-workflow-url]: https://github.com/dolanmiu/docx/actions [daviddm-image]: https://david-dm.org/dolanmiu/docx.svg?theme=shields.io [daviddm-url]: https://david-dm.org/dolanmiu/docx [snky-image]: https://snyk.io/test/github/dolanmiu/docx/badge.svg diff --git a/demo/1-basic.ts b/demo/1-basic.ts index 7db8870259..eb417f52b4 100644 --- a/demo/1-basic.ts +++ b/demo/1-basic.ts @@ -16,9 +16,9 @@ doc.addSection({ bold: true, }), new TextRun({ - text: "Github is the best", + text: "\tGithub is the best", bold: true, - }).tab(), + }), ], }), ], diff --git a/demo/10-my-cv.ts b/demo/10-my-cv.ts index b3e7c55e01..484a9c249c 100644 --- a/demo/10-my-cv.ts +++ b/demo/10-my-cv.ts @@ -204,7 +204,10 @@ class DocumentCreator { alignment: AlignmentType.CENTER, children: [ new TextRun(`Mobile: ${phoneNumber} | LinkedIn: ${profileUrl} | Email: ${email}`), - new TextRun("Address: 58 Elm Avenue, Kent ME4 6ER, UK").break(), + new TextRun({ + text: "Address: 58 Elm Avenue, Kent ME4 6ER, UK", + break: 1, + }), ], }); } @@ -238,9 +241,9 @@ class DocumentCreator { bold: true, }), new TextRun({ - text: dateText, + text: `\t${dateText}`, bold: true, - }).tab(), + }), ], }); } diff --git a/demo/11-declaritive-styles-2.ts b/demo/11-declaritive-styles-2.ts index 3a0154a0fb..2f4ed78098 100644 --- a/demo/11-declaritive-styles-2.ts +++ b/demo/11-declaritive-styles-2.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import { AlignmentType, + convertInchesToTwip, Document, Footer, HeadingLevel, @@ -18,13 +19,8 @@ import { const doc = new Document({ styles: { - paragraphStyles: [ - { - id: "Heading1", - name: "Heading 1", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + default: { + heading1: { run: { font: "Calibri", size: 52, @@ -40,12 +36,7 @@ const doc = new Document({ spacing: { line: 340 }, }, }, - { - id: "Heading2", - name: "Heading 2", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + heading2: { run: { font: "Calibri", size: 26, @@ -55,12 +46,7 @@ const doc = new Document({ spacing: { line: 340 }, }, }, - { - id: "Heading3", - name: "Heading 3", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + heading3: { run: { font: "Calibri", size: 26, @@ -70,12 +56,7 @@ const doc = new Document({ spacing: { line: 276 }, }, }, - { - id: "Heading4", - name: "Heading 4", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + heading4: { run: { font: "Calibri", size: 26, @@ -85,6 +66,8 @@ const doc = new Document({ alignment: AlignmentType.JUSTIFIED, }, }, + }, + paragraphStyles: [ { id: "normalPara", name: "Normal Para", @@ -128,7 +111,7 @@ const doc = new Document({ }, paragraph: { spacing: { line: 276 }, - indent: { left: 720 }, + indent: { left: convertInchesToTwip(0.5) }, }, }, { @@ -139,12 +122,6 @@ const doc = new Document({ spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 }, }, }, - { - id: "ListParagraph", - name: "List Paragraph", - basedOn: "Normal", - quickFormat: true, - }, ], }, }); diff --git a/demo/14-page-numbers.ts b/demo/14-page-numbers.ts index ae34300b5c..00b77cfe31 100644 --- a/demo/14-page-numbers.ts +++ b/demo/14-page-numbers.ts @@ -1,7 +1,7 @@ // Page numbers // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { AlignmentType, Document, Header, Packer, PageBreak, Paragraph, TextRun } from "../build"; +import { AlignmentType, Document, Header, Packer, PageBreak, PageNumber, Paragraph, TextRun } from "../build"; const doc = new Document(); @@ -11,7 +11,12 @@ doc.addSection({ children: [ new Paragraph({ alignment: AlignmentType.RIGHT, - children: [new TextRun("My Title "), new TextRun("Page ").pageNumber()], + children: [ + new TextRun("My Title "), + new TextRun({ + children: ["Page ", PageNumber.CURRENT], + }), + ], }), ], }), @@ -19,7 +24,12 @@ doc.addSection({ children: [ new Paragraph({ alignment: AlignmentType.RIGHT, - children: [new TextRun("First Page Header "), new TextRun("Page ").pageNumber()], + children: [ + new TextRun("First Page Header "), + new TextRun({ + children: ["Page ", PageNumber.CURRENT], + }), + ], }), ], }), diff --git a/demo/16-multiple-sections.ts b/demo/16-multiple-sections.ts index 5518eb5416..6f2e350b23 100644 --- a/demo/16-multiple-sections.ts +++ b/demo/16-multiple-sections.ts @@ -1,7 +1,7 @@ // Multiple sections and headers // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Footer, Header, Packer, PageNumberFormat, PageOrientation, Paragraph, TextRun } from "../build"; +import { Document, Footer, Header, Packer, PageNumber, PageNumberFormat, PageOrientation, Paragraph, TextRun } from "../build"; const doc = new Document(); @@ -53,7 +53,11 @@ doc.addSection({ default: new Header({ children: [ new Paragraph({ - children: [new TextRun("Page number: ").pageNumber()], + children: [ + new TextRun({ + children: ["Page number: ", PageNumber.CURRENT], + }), + ], }), ], }), @@ -69,7 +73,11 @@ doc.addSection({ default: new Header({ children: [ new Paragraph({ - children: [new TextRun("Page number: ").pageNumber()], + children: [ + new TextRun({ + children: ["Page number: ", PageNumber.CURRENT], + }), + ], }), ], }), @@ -90,7 +98,11 @@ doc.addSection({ default: new Header({ children: [ new Paragraph({ - children: [new TextRun("Page number: ").pageNumber()], + children: [ + new TextRun({ + children: ["Page number: ", PageNumber.CURRENT], + }), + ], }), ], }), diff --git a/demo/17-footnotes.ts b/demo/17-footnotes.ts index 3920d0dce8..a41f84a3c8 100644 --- a/demo/17-footnotes.ts +++ b/demo/17-footnotes.ts @@ -1,16 +1,54 @@ // Footnotes // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph } from "../build"; +import { Document, FootnoteReferenceRun, Packer, Paragraph, TextRun } from "../build"; -const doc = new Document(); - -doc.addSection({ - children: [new Paragraph("Hello World").referenceFootnote(1), new Paragraph("Hello World").referenceFootnote(2)], +const doc = new Document({ + footnotes: [ + new Paragraph("Foo"), + new Paragraph("Test"), + new Paragraph("My amazing reference"), + new Paragraph("Foo1"), + new Paragraph("Test1"), + new Paragraph("My amazing reference1"), + ], }); -doc.createFootnote(new Paragraph("Test")); -doc.createFootnote(new Paragraph("My amazing reference")); +doc.addSection({ + children: [ + new Paragraph({ + children: [ + new TextRun({ + children: ["Hello", new FootnoteReferenceRun(1)], + }), + new TextRun({ + children: [" World!", new FootnoteReferenceRun(2)], + }), + ], + }), + new Paragraph({ + children: [new TextRun("Hello World"), new FootnoteReferenceRun(3)], + }), + ], +}); + +doc.addSection({ + children: [ + new Paragraph({ + children: [ + new TextRun({ + children: ["Hello", new FootnoteReferenceRun(4)], + }), + new TextRun({ + children: [" World!", new FootnoteReferenceRun(5)], + }), + ], + }), + new Paragraph({ + children: [new TextRun("Hello World"), new FootnoteReferenceRun(6)], + }), + ], +}); Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); diff --git a/demo/19-export-to-base64.ts b/demo/19-export-to-base64.ts index 676d844c8d..1d94cf5ff7 100644 --- a/demo/19-export-to-base64.ts +++ b/demo/19-export-to-base64.ts @@ -15,9 +15,9 @@ doc.addSection({ bold: true, }), new TextRun({ - text: "Bar", + text: "\tBar", bold: true, - }).tab(), + }), ], }), ], diff --git a/demo/2-declaritive-styles.ts b/demo/2-declaritive-styles.ts index eaf39daffe..deada8198a 100644 --- a/demo/2-declaritive-styles.ts +++ b/demo/2-declaritive-styles.ts @@ -1,24 +1,30 @@ // Example on how to customise the look at feel using Styles // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, Paragraph, TextRun, UnderlineType } from "../build"; +import { + AlignmentType, + convertInchesToTwip, + Document, + HeadingLevel, + LevelFormat, + Packer, + Paragraph, + TextRun, + UnderlineType, +} from "../build"; const doc = new Document({ creator: "Clippy", title: "Sample Document", description: "A brief example of using docx", styles: { - paragraphStyles: [ - { - id: "Heading1", - name: "Heading 1", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + default: { + heading1: { run: { size: 28, bold: true, italics: true, + color: "red", }, paragraph: { spacing: { @@ -26,12 +32,7 @@ const doc = new Document({ }, }, }, - { - id: "Heading2", - name: "Heading 2", - basedOn: "Normal", - next: "Normal", - quickFormat: true, + heading2: { run: { size: 26, bold: true, @@ -47,6 +48,13 @@ const doc = new Document({ }, }, }, + listParagraph: { + run: { + color: "#FF0000", + }, + }, + }, + paragraphStyles: [ { id: "aside", name: "Aside", @@ -58,7 +66,7 @@ const doc = new Document({ }, paragraph: { indent: { - left: 720, + left: convertInchesToTwip(0.5), }, spacing: { line: 276, @@ -74,23 +82,25 @@ const doc = new Document({ spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 }, }, }, + ], + }, + numbering: { + config: [ { - id: "ListParagraph", - name: "List Paragraph", - basedOn: "Normal", - quickFormat: true, + reference: "my-crazy-numbering", + levels: [ + { + level: 0, + format: LevelFormat.LOWER_LETTER, + text: "%1)", + alignment: AlignmentType.LEFT, + }, + ], }, ], }, }); -const numberedAbstract = doc.Numbering.createAbstractNumbering(); -numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left"); - -const letterNumbering = doc.Numbering.createConcreteNumbering(numberedAbstract); -const letterNumbering5 = doc.Numbering.createConcreteNumbering(numberedAbstract); -letterNumbering5.overrideLevel(0, 5); - doc.addSection({ children: [ new Paragraph({ @@ -105,21 +115,21 @@ doc.addSection({ new Paragraph({ text: "Option1", numbering: { - num: letterNumbering, + reference: "my-crazy-numbering", level: 0, }, }), new Paragraph({ text: "Option5 -- override 2 to 5", numbering: { - num: letterNumbering, + reference: "my-crazy-numbering", level: 0, }, }), new Paragraph({ text: "Option3", numbering: { - num: letterNumbering, + reference: "my-crazy-numbering", level: 0, }, }), @@ -152,11 +162,26 @@ doc.addSection({ text: "and then underlined ", underline: {}, }), + new TextRun({ + text: "and then emphasis-mark ", + emphasisMark: {}, + }), new TextRun({ text: "and back to normal.", }), ], }), + new Paragraph({ + style: "Strong", + children: [ + new TextRun({ + text: "Strong Style", + }), + new TextRun({ + text: " - Very strong.", + }), + ], + }), ], }); diff --git a/demo/21-bookmarks.ts b/demo/21-bookmarks.ts index cc0bac5517..632fcb212f 100644 --- a/demo/21-bookmarks.ts +++ b/demo/21-bookmarks.ts @@ -1,7 +1,7 @@ // This demo shows how to create bookmarks then link to them with internal hyperlinks // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, PageBreak, Paragraph } from "../build"; +import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun } from "../build"; const LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante."; @@ -12,17 +12,28 @@ const doc = new Document({ description: "A brief example of using docx with bookmarks and internal hyperlinks", }); -const anchorId = "anchorID"; - -// First create the bookmark -const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum"); -const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`); - doc.addSection({ + footers: { + default: new Footer({ + children: [ + new Paragraph({ + children: [ + new InternalHyperlink({ + child: new TextRun({ + text: "Click here!", + style: "Hyperlink", + }), + anchor: "myAnchorId", + }), + ], + }), + ], + }), + }, children: [ new Paragraph({ heading: HeadingLevel.HEADING_1, - children: [bookmark], + children: [new Bookmark("myAnchorId", "Lorem Ipsum")], }), new Paragraph("\n"), new Paragraph(LOREM_IPSUM), @@ -30,7 +41,15 @@ doc.addSection({ children: [new PageBreak()], }), new Paragraph({ - children: [hyperlink], + children: [ + new InternalHyperlink({ + child: new TextRun({ + text: "Anchor Text", + style: "Hyperlink", + }), + anchor: "myAnchorId", + }), + ], }), ], }); diff --git a/demo/22-right-to-left-text.ts b/demo/22-right-to-left-text.ts index 2c3984fb46..4ee344391c 100644 --- a/demo/22-right-to-left-text.ts +++ b/demo/22-right-to-left-text.ts @@ -1,7 +1,7 @@ // This demo shows right to left for special languages // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph, TextRun } from "../build"; +import { Document, Packer, Paragraph, Table, TableCell, TableRow, TextRun } from "../build"; const doc = new Document(); @@ -36,6 +36,31 @@ doc.addSection({ }), ], }), + new Table({ + visuallyRightToLeft: true, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("שלום עולם")], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("שלום עולם")], + }), + ], + }), + ], + }), ], }); diff --git a/demo/27-declaritive-styles-3.ts b/demo/27-declaritive-styles-3.ts index 8419467799..8737c69101 100644 --- a/demo/27-declaritive-styles-3.ts +++ b/demo/27-declaritive-styles-3.ts @@ -1,7 +1,7 @@ // Custom styles using JavaScript configuration // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, Paragraph, UnderlineType } from "../build"; +import { Document, convertInchesToTwip, HeadingLevel, Packer, Paragraph, UnderlineType } from "../build"; const doc = new Document({ styles: { @@ -17,7 +17,7 @@ const doc = new Document({ }, paragraph: { indent: { - left: 720, + left: convertInchesToTwip(0.5), }, spacing: { line: 276, diff --git a/demo/29-numbered-lists.ts b/demo/29-numbered-lists.ts index 740320e5f8..77f50381d1 100644 --- a/demo/29-numbered-lists.ts +++ b/demo/29-numbered-lists.ts @@ -1,23 +1,69 @@ // Numbered lists // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Numbering, Packer, Paragraph } from "../build"; +import { AlignmentType, convertInchesToTwip, Document, LevelFormat, Packer, Paragraph } from "../build"; -const doc = new Document(); - -const numbering = new Numbering(); - -const abstractNum = numbering.createAbstractNumbering(); -abstractNum.createLevel(0, "upperRoman", "%1", "start").indent({ left: 720, hanging: 260 }); - -const concrete = numbering.createConcreteNumbering(abstractNum); +const doc = new Document({ + numbering: { + config: [ + { + levels: [ + { + level: 0, + format: LevelFormat.UPPER_ROMAN, + text: "%1", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.18) }, + }, + }, + }, + ], + reference: "my-crazy-reference", + }, + { + levels: [ + { + level: 0, + format: LevelFormat.DECIMAL, + text: "%1", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.18) }, + }, + }, + }, + ], + reference: "my-number-numbering-reference", + }, + { + levels: [ + { + level: 0, + format: LevelFormat.DECIMAL_ZERO, + text: "[%1]", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.18) }, + }, + }, + }, + ], + reference: "padded-numbering-reference", + }, + ], + }, +}); doc.addSection({ children: [ new Paragraph({ text: "line with contextual spacing", numbering: { - num: concrete, + reference: "my-crazy-reference", level: 0, }, contextualSpacing: true, @@ -28,7 +74,7 @@ doc.addSection({ new Paragraph({ text: "line with contextual spacing", numbering: { - num: concrete, + reference: "my-crazy-reference", level: 0, }, contextualSpacing: true, @@ -39,7 +85,7 @@ doc.addSection({ new Paragraph({ text: "line without contextual spacing", numbering: { - num: concrete, + reference: "my-crazy-reference", level: 0, }, contextualSpacing: false, @@ -50,7 +96,7 @@ doc.addSection({ new Paragraph({ text: "line without contextual spacing", numbering: { - num: concrete, + reference: "my-crazy-reference", level: 0, }, contextualSpacing: false, @@ -58,6 +104,160 @@ doc.addSection({ before: 200, }, }), + new Paragraph({ + text: "Step 1 - Add sugar", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "Step 2 - Add wheat", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "Step 3 - Put in oven", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "test", + numbering: { + reference: "padded-numbering-reference", + level: 0, + }, + }), ], }); diff --git a/demo/3-numbering-and-bullet-points.ts b/demo/3-numbering-and-bullet-points.ts index e87e6616d2..375c1439a7 100644 --- a/demo/3-numbering-and-bullet-points.ts +++ b/demo/3-numbering-and-bullet-points.ts @@ -1,46 +1,91 @@ // Numbering and bullet points example // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Numbering, Packer, Paragraph } from "../build"; +import { AlignmentType, convertInchesToTwip, Document, LevelFormat, Packer, Paragraph } from "../build"; -const doc = new Document(); - -const numbering = new Numbering(); - -const abstractNum = numbering.createAbstractNumbering(); -abstractNum.createLevel(0, "upperRoman", "%1", "start").indent({ left: 720, hanging: 260 }); -abstractNum.createLevel(1, "decimal", "%2.", "start").indent({ left: 1440, hanging: 980 }); -abstractNum.createLevel(2, "lowerLetter", "%3)", "start").indent({ left: 2160, hanging: 1700 }); - -const concrete = numbering.createConcreteNumbering(abstractNum); +const doc = new Document({ + numbering: { + config: [ + { + reference: "my-crazy-numbering", + levels: [ + { + level: 0, + format: LevelFormat.UPPER_ROMAN, + text: "%1", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.18) }, + }, + }, + }, + { + level: 1, + format: LevelFormat.DECIMAL, + text: "%2.", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(1), hanging: convertInchesToTwip(0.68) }, + }, + }, + }, + { + level: 2, + format: LevelFormat.LOWER_LETTER, + text: "%3)", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(1.5), hanging: convertInchesToTwip(1.18) }, + }, + }, + }, + { + level: 3, + format: LevelFormat.UPPER_LETTER, + text: "%4)", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: 2880, hanging: 2420 }, + }, + }, + }, + ], + }, + ], + }, +}); doc.addSection({ children: [ new Paragraph({ text: "Hey you", numbering: { - num: concrete, + reference: "my-crazy-numbering", level: 0, }, }), new Paragraph({ text: "What's up fam", numbering: { - num: concrete, + reference: "my-crazy-numbering", level: 1, }, }), new Paragraph({ text: "Hello World 2", numbering: { - num: concrete, + reference: "my-crazy-numbering", level: 1, }, }), new Paragraph({ text: "Yeah boi", numbering: { - num: concrete, + reference: "my-crazy-numbering", level: 2, }, }), @@ -68,6 +113,27 @@ doc.addSection({ level: 3, }, }), + new Paragraph({ + text: "101 MSXFM", + numbering: { + reference: "my-crazy-numbering", + level: 3, + }, + }), + new Paragraph({ + text: "back to level 1", + numbering: { + reference: "my-crazy-numbering", + level: 1, + }, + }), + new Paragraph({ + text: "back to level 0", + numbering: { + reference: "my-crazy-numbering", + level: 0, + }, + }), ], }); diff --git a/demo/31-tables.ts b/demo/31-tables.ts index 7daec1506d..24fc6030f8 100644 --- a/demo/31-tables.ts +++ b/demo/31-tables.ts @@ -1,7 +1,7 @@ // Example of how you would create a table and add data to it // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build"; +import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign, TextDirection } from "../build"; const doc = new Document(); @@ -17,6 +17,14 @@ const table = new Table({ children: [new Paragraph({}), new Paragraph({})], verticalAlign: VerticalAlign.CENTER, }), + new TableCell({ + children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})], + textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT, + }), + new TableCell({ + children: [new Paragraph({ text: "top to bottom" }), new Paragraph({})], + textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT, + }), ], }), new TableRow({ @@ -38,6 +46,22 @@ const table = new Table({ ], verticalAlign: VerticalAlign.CENTER, }), + new TableCell({ + children: [ + new Paragraph({ + text: "Text above should be vertical from bottom to top", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [ + new Paragraph({ + text: "Text above should be vertical from top to bottom", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), ], }), ], diff --git a/demo/32-merge-and-shade-table-cells.ts b/demo/32-merge-and-shade-table-cells.ts index 77d6815d1e..284b456e05 100644 --- a/demo/32-merge-and-shade-table-cells.ts +++ b/demo/32-merge-and-shade-table-cells.ts @@ -1,7 +1,21 @@ // Example of how you would merge cells together (Rows and Columns) and apply shading +// Also includes an example on how to center tables // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, WidthType } from "../build"; +import { + AlignmentType, + BorderStyle, + convertInchesToTwip, + Document, + HeadingLevel, + Packer, + Paragraph, + ShadingType, + Table, + TableCell, + TableRow, + WidthType, +} from "../build"; const doc = new Document(); @@ -29,16 +43,17 @@ const table = new Table({ }); const table2 = new Table({ + alignment: AlignmentType.CENTER, rows: [ new TableRow({ children: [ new TableCell({ children: [new Paragraph("World")], margins: { - top: 1000, - bottom: 1000, - left: 1000, - right: 1000, + top: convertInchesToTwip(0.69), + bottom: convertInchesToTwip(0.69), + left: convertInchesToTwip(0.69), + right: convertInchesToTwip(0.69), }, columnSpan: 3, }), @@ -62,10 +77,11 @@ const table2 = new Table({ size: 100, type: WidthType.AUTO, }, - columnWidths: [1000, 1000, 1000], + columnWidths: [convertInchesToTwip(0.69), convertInchesToTwip(0.69), convertInchesToTwip(0.69)], }); const table3 = new Table({ + alignment: AlignmentType.CENTER, rows: [ new TableRow({ children: [ @@ -116,14 +132,14 @@ const table3 = new Table({ }), ], width: { - size: 7000, + size: convertInchesToTwip(4.86), type: WidthType.DXA, }, margins: { - top: 400, - bottom: 400, - right: 400, - left: 400, + top: convertInchesToTwip(0.27), + bottom: convertInchesToTwip(0.27), + right: convertInchesToTwip(0.27), + left: convertInchesToTwip(0.27), }, }); @@ -181,7 +197,7 @@ const table5 = new Table({ new TableRow({ children: [ new TableCell({ - children: [], + children: [new Paragraph("1,0")], }), new TableCell({ children: [new Paragraph("1,2")], @@ -192,10 +208,10 @@ const table5 = new Table({ new TableRow({ children: [ new TableCell({ - children: [], + children: [new Paragraph("2,0")], }), new TableCell({ - children: [], + children: [new Paragraph("2,1")], }), ], }), @@ -206,6 +222,161 @@ const table5 = new Table({ }, }); +const borders = { + top: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + bottom: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + left: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + right: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, +}; + +const table6 = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + borders, + children: [new Paragraph("0,0")], + rowSpan: 2, + }), + new TableCell({ + borders, + children: [new Paragraph("0,1")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + borders, + children: [new Paragraph("1,1")], + rowSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + borders, + children: [new Paragraph("2,0")], + }), + ], + }), + ], + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, +}); + +const table7 = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("0,0")], + }), + new TableCell({ + children: [new Paragraph("0,1")], + }), + new TableCell({ + children: [new Paragraph("0,2")], + rowSpan: 2, + }), + new TableCell({ + children: [new Paragraph("0,3")], + rowSpan: 3, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("1,0")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("2,0")], + columnSpan: 2, + }), + new TableCell({ + children: [new Paragraph("2,2")], + rowSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("3,0")], + }), + new TableCell({ + children: [new Paragraph("3,1")], + }), + new TableCell({ + children: [new Paragraph("3,3")], + }), + ], + }), + ], + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, +}); + +const table8 = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ children: [new Paragraph("1,1")] }), + new TableCell({ children: [new Paragraph("1,2")] }), + new TableCell({ children: [new Paragraph("1,3")] }), + new TableCell({ children: [new Paragraph("1,4")], rowSpan: 4, borders }), + ], + }), + new TableRow({ + children: [ + new TableCell({ children: [new Paragraph("2,1")] }), + new TableCell({ children: [new Paragraph("2,2")] }), + new TableCell({ children: [new Paragraph("2,3")], rowSpan: 3 }), + ], + }), + new TableRow({ + children: [ + new TableCell({ children: [new Paragraph("3,1")] }), + new TableCell({ children: [new Paragraph("3,2")], rowSpan: 2 }), + ], + }), + new TableRow({ + children: [new TableCell({ children: [new Paragraph("4,1")] })], + }), + ], + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, +}); + doc.addSection({ children: [ table, @@ -219,10 +390,16 @@ doc.addSection({ heading: HeadingLevel.HEADING_2, }), table3, - new Paragraph("Merging columns"), + new Paragraph("Merging columns 1"), table4, - new Paragraph("More Merging columns"), + new Paragraph("Merging columns 2"), table5, + new Paragraph("Merging columns 3"), + table6, + new Paragraph("Merging columns 4"), + table7, + new Paragraph("Merging columns 5"), + table8, ], }); diff --git a/demo/34-floating-tables.ts b/demo/34-floating-tables.ts index dadf80f9da..aa8128de7e 100644 --- a/demo/34-floating-tables.ts +++ b/demo/34-floating-tables.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import { Document, + OverlapType, Packer, Paragraph, RelativeHorizontalPosition, @@ -43,6 +44,7 @@ const table = new Table({ verticalAnchor: TableAnchorType.MARGIN, relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT, relativeVerticalPosition: RelativeVerticalPosition.BOTTOM, + overlap: OverlapType.NEVER, }, width: { size: 4535, diff --git a/demo/35-hyperlinks.ts b/demo/35-hyperlinks.ts index 6392299b84..3e45e4c342 100644 --- a/demo/35-hyperlinks.ts +++ b/demo/35-hyperlinks.ts @@ -1,15 +1,91 @@ // Example on how to add hyperlinks to websites // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph } from "../build"; +import { Document, ExternalHyperlink, Footer, FootnoteReferenceRun, Media, Packer, Paragraph, TextRun } from "../build"; -const doc = new Document(); -const link = doc.createHyperlink("http://www.example.com", "Hyperlink"); +const doc = new Document({ + footnotes: [ + new Paragraph({ + children: [ + new TextRun("Click here for the "), + new ExternalHyperlink({ + child: new TextRun({ + text: "Footnotes external hyperlink", + style: "Hyperlink", + }), + link: "http://www.example.com", + }), + ], + }), + ], +}); + +const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); doc.addSection({ + footers: { + default: new Footer({ + children: [ + new Paragraph({ + children: [ + new TextRun("Click here for the "), + new ExternalHyperlink({ + child: new TextRun({ + text: "Footer external hyperlink", + style: "Hyperlink", + }), + link: "http://www.example.com", + }), + ], + }), + ], + }), + }, + headers: { + default: new Footer({ + children: [ + new Paragraph({ + children: [ + new TextRun("Click here for the "), + new ExternalHyperlink({ + child: new TextRun({ + text: "Header external hyperlink", + style: "Hyperlink", + }), + link: "http://www.google.com", + }), + ], + }), + ], + }), + }, children: [ new Paragraph({ - children: [link], + children: [ + new ExternalHyperlink({ + child: new TextRun({ + text: "Anchor Text", + style: "Hyperlink", + }), + link: "http://www.example.com", + }), + new FootnoteReferenceRun(1) + ], + }), + new Paragraph({ + children: [ + new ExternalHyperlink({ + child: image1, + link: "http://www.google.com", + }), + new ExternalHyperlink({ + child: new TextRun({ + text: "BBC News Link", + style: "Hyperlink", + }), + link: "https://www.bbc.co.uk/news", + }), + ], }), ], }); diff --git a/demo/39-page-numbers.ts b/demo/39-page-numbers.ts index edc9c411f9..2ab61419ef 100644 --- a/demo/39-page-numbers.ts +++ b/demo/39-page-numbers.ts @@ -1,7 +1,7 @@ // Example how to display page numbers // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { AlignmentType, Document, Footer, Header, Packer, PageNumberFormat, Paragraph, TextRun } from "../build"; +import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, PageNumberFormat, Paragraph, TextRun } from "../build"; const doc = new Document({}); @@ -9,9 +9,17 @@ doc.addSection({ headers: { default: new Header({ children: [ - new Paragraph("Foo Bar corp. ") - .addRun(new TextRun("Page Number ").pageNumber()) - .addRun(new TextRun(" to ").numberOfTotalPages()), + new Paragraph({ + children: [ + new TextRun("Foo Bar corp. "), + new TextRun({ + children: ["Page Number ", PageNumber.CURRENT], + }), + new TextRun({ + children: [" to ", PageNumber.TOTAL_PAGES], + }), + ], + }), ], }), }, @@ -19,11 +27,17 @@ doc.addSection({ default: new Footer({ children: [ new Paragraph({ - text: "Foo Bar corp. ", alignment: AlignmentType.CENTER, - }) - .addRun(new TextRun("Page Number: ").pageNumber()) - .addRun(new TextRun(" to ").numberOfTotalPages()), + children: [ + new TextRun("Foo Bar corp. "), + new TextRun({ + children: ["Page Number: ", PageNumber.CURRENT], + }), + new TextRun({ + children: [" to ", PageNumber.TOTAL_PAGES], + }), + ], + }), ], }), }, @@ -32,11 +46,21 @@ doc.addSection({ pageNumberFormatType: PageNumberFormat.DECIMAL, }, children: [ - new Paragraph("Hello World 1").pageBreak(), - new Paragraph("Hello World 2").pageBreak(), - new Paragraph("Hello World 3").pageBreak(), - new Paragraph("Hello World 4").pageBreak(), - new Paragraph("Hello World 5").pageBreak(), + new Paragraph({ + children: [new TextRun("Hello World 1"), new PageBreak()], + }), + new Paragraph({ + children: [new TextRun("Hello World 2"), new PageBreak()], + }), + new Paragraph({ + children: [new TextRun("Hello World 3"), new PageBreak()], + }), + new Paragraph({ + children: [new TextRun("Hello World 4"), new PageBreak()], + }), + new Paragraph({ + children: [new TextRun("Hello World 5"), new PageBreak()], + }), ], }); diff --git a/demo/4-basic-table.ts b/demo/4-basic-table.ts index 593fe821a5..287e54808a 100644 --- a/demo/4-basic-table.ts +++ b/demo/4-basic-table.ts @@ -1,11 +1,95 @@ // Example of how you would create a table and add data to it // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; +import { Document, Packer, Paragraph, Table, TableCell, TableRow, WidthType } from "../build"; const doc = new Document(); const table = new Table({ + columnWidths: [3505, 5505], + rows: [ + new TableRow({ + children: [ + new TableCell({ + width: { + size: 3505, + type: WidthType.DXA, + }, + children: [new Paragraph("Hello")], + }), + new TableCell({ + width: { + size: 5505, + type: WidthType.DXA, + }, + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + width: { + size: 3505, + type: WidthType.DXA, + }, + children: [], + }), + new TableCell({ + width: { + size: 5505, + type: WidthType.DXA, + }, + children: [new Paragraph("World")], + }), + ], + }), + ], +}); + +const table2 = new Table({ + columnWidths: [4505, 4505], + rows: [ + new TableRow({ + children: [ + new TableCell({ + width: { + size: 4505, + type: WidthType.DXA, + }, + children: [new Paragraph("Hello")], + }), + new TableCell({ + width: { + size: 4505, + type: WidthType.DXA, + }, + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + width: { + size: 4505, + type: WidthType.DXA, + }, + children: [], + }), + new TableCell({ + width: { + size: 4505, + type: WidthType.DXA, + }, + children: [new Paragraph("World")], + }), + ], + }), + ], +}); + +const table3 = new Table({ rows: [ new TableRow({ children: [ @@ -31,7 +115,14 @@ const table = new Table({ }); doc.addSection({ - children: [table], + children: [ + new Paragraph({ text: "Table with skewed widths" }), + table, + new Paragraph({ text: "Table with equal widths" }), + table2, + new Paragraph({ text: "Table without setting widths" }), + table3, + ], }); Packer.toBuffer(doc).then((buffer) => { diff --git a/demo/44-multiple-columns.ts b/demo/44-multiple-columns.ts index 3985486620..6e01e874e7 100644 --- a/demo/44-multiple-columns.ts +++ b/demo/44-multiple-columns.ts @@ -35,6 +35,22 @@ doc.addSection({ ], }); +doc.addSection({ + properties: { + column: { + space: 708, + count: 2, + separate: true, + }, + }, + children: [ + new Paragraph("This text will be split into 2 columns on a page."), + new Paragraph( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + ), + ], +}); + Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); }); diff --git a/demo/46-shading-text.ts b/demo/46-shading-text.ts index 61f3f3d984..e662e6dffe 100644 --- a/demo/46-shading-text.ts +++ b/demo/46-shading-text.ts @@ -28,6 +28,18 @@ doc.addSection({ }), ], }), + new Paragraph({ + shading: { + type: ShadingType.DIAGONAL_CROSS, + color: "00FFFF", + fill: "FF0000", + }, + children: [ + new TextRun({ + text: "Hello World for entire paragraph", + }), + ], + }), ], }), }, diff --git a/demo/47-number-of-total-pages-section.ts b/demo/47-number-of-total-pages-section.ts index 988206e524..7e8cf91b2c 100644 --- a/demo/47-number-of-total-pages-section.ts +++ b/demo/47-number-of-total-pages-section.ts @@ -1,7 +1,7 @@ // Multiple sections with total number of pages in each section // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { AlignmentType, Document, Packer, PageNumberFormat, TextRun, Header, Paragraph, Footer, PageBreak } from "../build"; +import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, PageNumberFormat, Paragraph, TextRun } from "../build"; const doc = new Document(); @@ -10,8 +10,12 @@ const header = new Header({ new Paragraph({ children: [ new TextRun("Header on another page"), - new TextRun("Page Number: ").pageNumber(), - new TextRun(" to ").numberOfTotalPagesSection(), + new TextRun({ + children: ["Page number: ", PageNumber.CURRENT], + }), + new TextRun({ + children: [" to ", PageNumber.TOTAL_PAGES_IN_SECTION], + }), ], alignment: AlignmentType.CENTER, }), diff --git a/demo/48-vertical-align.ts b/demo/48-vertical-align.ts new file mode 100644 index 0000000000..35181d271c --- /dev/null +++ b/demo/48-vertical-align.ts @@ -0,0 +1,31 @@ +// Example of making content of section vertically aligned +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, SectionVerticalAlignValue, TextRun } from "../build"; + +const doc = new Document(); + +doc.addSection({ + properties: { + verticalAlign: SectionVerticalAlignValue.CENTER, + }, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + new TextRun({ + text: "\tGithub is the best", + bold: true, + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/49-table-borders.ts b/demo/49-table-borders.ts new file mode 100644 index 0000000000..75dd89c49f --- /dev/null +++ b/demo/49-table-borders.ts @@ -0,0 +1,167 @@ +// Add custom borders and no-borders to the table itself +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { + BorderStyle, + Document, + HeadingLevel, + Packer, + Paragraph, + Table, + TableBorders, + TableCell, + TableRow, + TextDirection, + VerticalAlign, +} from "../build"; + +const doc = new Document(); + +const table = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + borders: { + top: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + bottom: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + left: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + right: { + style: BorderStyle.DASH_SMALL_GAP, + size: 1, + color: "red", + }, + }, + children: [new Paragraph("Hello")], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("World")], + }), + ], + }), + ], +}); + +// Using the no-border convenience object. It is the same as writing this manually: +// const borders = { +// top: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// bottom: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// left: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// right: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// insideHorizontal: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// insideVertical: { +// style: BorderStyle.NONE, +// size: 0, +// color: "auto", +// }, +// }; +const noBorderTable = new Table({ + borders: TableBorders.NONE, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph({}), new Paragraph({})], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [new Paragraph({}), new Paragraph({})], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})], + textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT, + }), + new TableCell({ + children: [new Paragraph({ text: "top to bottom" }), new Paragraph({})], + textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [ + new Paragraph({ + text: + "Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah", + heading: HeadingLevel.HEADING_1, + }), + ], + }), + new TableCell({ + children: [ + new Paragraph({ + text: "This text should be in the middle of the cell", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [ + new Paragraph({ + text: "Text above should be vertical from bottom to top", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [ + new Paragraph({ + text: "Text above should be vertical from top to bottom", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + ], + }), + ], +}); + +doc.addSection({ children: [table, new Paragraph("Hello"), noBorderTable] }); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/5-images.ts b/demo/5-images.ts index 260fd25f15..3c752d9a58 100644 --- a/demo/5-images.ts +++ b/demo/5-images.ts @@ -22,6 +22,7 @@ const image4 = Media.addImage(doc, fs.readFileSync("./demo/images/parrots.bmp")) const image5 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); const image6 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"), 200, 200, { floating: { + zIndex: 10, horizontalPosition: { offset: 1014400, }, @@ -33,6 +34,7 @@ const image6 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"), 2 const image7 = Media.addImage(doc, fs.readFileSync("./demo/images/cat.jpg"), 200, 200, { floating: { + zIndex: 5, horizontalPosition: { relative: HorizontalPositionRelativeFrom.PAGE, align: HorizontalPositionAlign.RIGHT, diff --git a/demo/50-readme-demo.ts b/demo/50-readme-demo.ts new file mode 100644 index 0000000000..6b1cc0ecab --- /dev/null +++ b/demo/50-readme-demo.ts @@ -0,0 +1,61 @@ +// Simple example to add text to a document +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, HeadingLevel, Media, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build"; + +const doc = new Document(); + +const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); +const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); + +const table = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph(image1)], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [ + new Paragraph({ + text: "Hello", + heading: HeadingLevel.HEADING_1, + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [ + new Paragraph({ + text: "World", + heading: HeadingLevel.HEADING_1, + }), + ], + }), + new TableCell({ + children: [new Paragraph(image1)], + }), + ], + }), + ], +}); + +doc.addSection({ + children: [ + new Paragraph({ + text: "Hello World", + heading: HeadingLevel.HEADING_1, + }), + table, + new Paragraph(image2), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/51-character-styles.ts b/demo/51-character-styles.ts new file mode 100644 index 0000000000..a6064a4ddc --- /dev/null +++ b/demo/51-character-styles.ts @@ -0,0 +1,57 @@ +// Custom character styles using JavaScript configuration +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, TextRun } from "../build"; + +const doc = new Document({ + styles: { + characterStyles: [ + { + id: "myRedStyle", + name: "My Wonky Style", + basedOn: "Normal", + run: { + color: "990000", + italics: true, + }, + }, + { + id: "strong", + name: "Strong", + basedOn: "Normal", + run: { + bold: true, + }, + }, + ], + }, +}); + +doc.addSection({ + children: [ + new Paragraph({ + children: [ + new TextRun({ + text: "Foo bar", + style: "myRedStyle", + }), + ], + }), + new Paragraph({ + children: [ + new TextRun({ + text: "First Word", + style: "strong", + }), + new TextRun({ + text: + " - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/52-japanese.ts b/demo/52-japanese.ts new file mode 100644 index 0000000000..5339c4b3a9 --- /dev/null +++ b/demo/52-japanese.ts @@ -0,0 +1,37 @@ +// Japanese text - Need to use a Japanese font +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, HeadingLevel, Packer, Paragraph } from "../build"; + +const doc = new Document({ + styles: { + paragraphStyles: [ + { + id: "Normal", + name: "Normal", + basedOn: "Normal", + next: "Normal", + quickFormat: true, + run: { + font: "MS Gothic", + }, + }, + ], + }, +}); + +doc.addSection({ + children: [ + new Paragraph({ + text: "KFCを食べるのが好き", + heading: HeadingLevel.HEADING_1, + }), + new Paragraph({ + text: "こんにちは", + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/53-chinese.ts b/demo/53-chinese.ts new file mode 100644 index 0000000000..eee6eb9032 --- /dev/null +++ b/demo/53-chinese.ts @@ -0,0 +1,55 @@ +// Chinese text - Chinese text need to use a Chinese font. And ascii text need to use a ascii font. +// Different from the `52-japanese.ts`. +// `52-japanese.ts` will set all characters to use Japanese font. +// `53-chinese.ts` will set Chinese characters to use Chinese font, and set ascii characters to use ascii font. + +// Note that if the OS have not install `KaiTi` font, this demo doesn't work. + +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "../build"; + +const doc = new Document({ + styles: { + paragraphStyles: [ + { + id: "Normal", + name: "Normal", + basedOn: "Normal", + next: "Normal", + quickFormat: true, + run: { + font: { + ascii: "Times", + eastAsia: "KaiTi", + }, + }, + }, + ], + }, +}); + +doc.addSection({ + children: [ + new Paragraph({ + text: "中文和英文 Chinese and English", + heading: HeadingLevel.HEADING_1, + }), + new Paragraph({ + text: "中文和英文 Chinese and English", + }), + new Paragraph({ + children: [ + new TextRun({ + text: "中文和英文 Chinese and English", + font: { eastAsia: "SimSun" }, // set eastAsia to "SimSun". + // The ascii characters will use the default font ("Times") specified in paragraphStyles + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/54-custom-properties.ts b/demo/54-custom-properties.ts new file mode 100644 index 0000000000..4aad3864c9 --- /dev/null +++ b/demo/54-custom-properties.ts @@ -0,0 +1,30 @@ +// Custom Properties +// Custom properties are incredibly useful if you want to be able to apply quick parts or custom cover pages +// to the document in Word after the document has been generated. Standard properties (such as creator, title +// and subject) cover typical use cases, but sometimes custom properties are required. + +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer } from "../build"; + +const doc = new Document( + // Standard properties + { + creator: "Creator", + title: "Title", + subject: "Subject", + description: "Description", + customProperties: [ + { name: "Subtitle", value: "Subtitle" }, + { name: "Address", value: "Address" }, + ], + }, + // No file properties + {}, + // No sections + [], +); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/54-track-revisions.ts b/demo/54-track-revisions.ts new file mode 100644 index 0000000000..e035fbb18a --- /dev/null +++ b/demo/54-track-revisions.ts @@ -0,0 +1,146 @@ +// Track Revisions aka. "Track Changes" +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { + AlignmentType, + DeletedTextRun, + Document, + Footer, + FootnoteReferenceRun, + InsertedTextRun, + Packer, + PageNumber, + Paragraph, + ShadingType, + TextRun, +} from "../build"; + +/* + For reference, see + - https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.insertedrun + - https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.deletedrun + + The method `addTrackRevisions()` adds an element `` to the `settings.xml` file. This specifies that the application shall track *new* revisions made to the existing document. + See also https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.trackrevisions + + Note that this setting enables to track *new changes* after teh file is generated, so this example will still show inserted and deleted text runs when you remove it. +*/ + +const doc = new Document({ + footnotes: [ + new Paragraph({ + children: [ + new TextRun("This is a footnote"), + new DeletedTextRun({ + text: " with some extra text which was deleted", + id: 0, + author: "Firstname Lastname", + date: "2020-10-06T09:05:00Z", + }), + new InsertedTextRun({ + text: " and new content", + id: 1, + author: "Firstname Lastname", + date: "2020-10-06T09:05:00Z", + }), + ], + }), + ], + features: { + trackRevisions: true, + }, +}); + +const paragraph = new Paragraph({ + children: [ + new TextRun("This is a simple demo "), + new TextRun({ + text: "on how to ", + }), + new InsertedTextRun({ + text: "mark a text as an insertion ", + id: 0, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }), + new DeletedTextRun({ + text: "or a deletion.", + id: 1, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }), + ], +}); + +doc.addSection({ + properties: {}, + children: [ + paragraph, + new Paragraph({ + children: [ + new TextRun("This is a demo "), + new DeletedTextRun({ + break: 1, + text: "in order", + color: "red", + bold: true, + size: 24, + font: { + name: "Garamond", + }, + shading: { + type: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "00FFFF", + fill: "FF0000", + }, + id: 2, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }), + new InsertedTextRun({ + text: "to show how to ", + bold: false, + id: 3, + author: "Firstname Lastname", + date: "2020-10-06T09:05:00Z", + }), + new TextRun({ + bold: true, + children: ["\tuse Inserted and Deleted TextRuns.", new FootnoteReferenceRun(1)], + }), + ], + }), + ], + footers: { + default: new Footer({ + children: [ + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun("Awesome LLC"), + new TextRun({ + children: ["Page Number: ", PageNumber.CURRENT], + }), + new DeletedTextRun({ + children: [" to ", PageNumber.TOTAL_PAGES], + id: 4, + author: "Firstname Lastname", + date: "2020-10-06T09:05:00Z", + }), + new InsertedTextRun({ + children: [" from ", PageNumber.TOTAL_PAGES], + bold: true, + id: 5, + author: "Firstname Lastname", + date: "2020-10-06T09:05:00Z", + }), + ], + }), + ], + }), + }, +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/55-math.ts b/demo/55-math.ts new file mode 100644 index 0000000000..2a240986d0 --- /dev/null +++ b/demo/55-math.ts @@ -0,0 +1,294 @@ +// Simple example to add text to a document +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { + Document, + Math, + MathAngledBrackets, + MathCurlyBrackets, + MathFraction, + MathFunction, + MathPreSubSuperScript, + MathRadical, + MathRoundBrackets, + MathRun, + MathSquareBrackets, + MathSubScript, + MathSubSuperScript, + MathSum, + MathSuperScript, + Packer, + Paragraph, + TextRun, +} from "../build"; + +const doc = new Document(); + +doc.addSection({ + properties: {}, + children: [ + new Paragraph({ + children: [ + new Math({ + children: [ + new MathRun("2+2"), + new MathFraction({ + numerator: [new MathRun("hi")], + denominator: [new MathRun("2")], + }), + ], + }), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathFraction({ + numerator: [ + new MathRun("1"), + new MathRadical({ + children: [new MathRun("2")], + }), + ], + denominator: [new MathRun("2")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSum({ + children: [new MathRun("test")], + }), + new MathSum({ + children: [ + new MathSuperScript({ + children: [new MathRun("e")], + superScript: [new MathRun("2")], + }), + ], + subScript: [new MathRun("i")], + }), + new MathSum({ + children: [ + new MathRadical({ + children: [new MathRun("i")], + }), + ], + subScript: [new MathRun("i")], + superScript: [new MathRun("10")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSuperScript({ + children: [new MathRun("test")], + superScript: [new MathRun("hello")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSubScript({ + children: [new MathRun("test")], + subScript: [new MathRun("hello")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSubScript({ + children: [new MathRun("x")], + subScript: [ + new MathSuperScript({ + children: [new MathRun("y")], + superScript: [new MathRun("2")], + }), + ], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSubSuperScript({ + children: [new MathRun("test")], + superScript: [new MathRun("hello")], + subScript: [new MathRun("world")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathPreSubSuperScript({ + children: [new MathRun("test")], + superScript: [new MathRun("hello")], + subScript: [new MathRun("world")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSubScript({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + subScript: [new MathRun("4")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathSubScript({ + children: [ + new MathRadical({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + degree: [new MathRun("4")], + }), + ], + subScript: [new MathRun("x")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathRadical({ + children: [new MathRun("4")], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathFunction({ + name: [ + new MathSuperScript({ + children: [new MathRun("cos")], + superScript: [new MathRun("-1")], + }), + ], + children: [new MathRun("100")], + }), + new MathRun("×"), + new MathFunction({ + name: [new MathRun("sin")], + children: [new MathRun("360")], + }), + new MathRun("= x"), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathRoundBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + }), + new MathSquareBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + }), + new MathCurlyBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + }), + new MathAngledBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], + }), + ], + }), + ], + }), + new Paragraph({ + children: [ + new Math({ + children: [ + new MathFraction({ + numerator: [ + new MathRadical({ + children: [new MathRun("4")], + }), + ], + denominator: [new MathRun("2a")], + }), + ], + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/56-background-color.ts b/demo/56-background-color.ts new file mode 100644 index 0000000000..6e8658fd00 --- /dev/null +++ b/demo/56-background-color.ts @@ -0,0 +1,33 @@ +// Change background colour of whole document +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, TextRun } from "../build"; + +const doc = new Document({ + background: { + color: "C45911", + }, +}); + +doc.addSection({ + properties: {}, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + new TextRun({ + text: "\tGithub is the best", + bold: true, + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/57-add-parent-numbered-lists.ts b/demo/57-add-parent-numbered-lists.ts new file mode 100644 index 0000000000..e35cd06a27 --- /dev/null +++ b/demo/57-add-parent-numbered-lists.ts @@ -0,0 +1,88 @@ +// Numbered lists - Add parent number in sub number +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { AlignmentType, convertInchesToTwip, Document, HeadingLevel, LevelFormat, Packer, Paragraph } from "../build"; + +const doc = new Document({ + numbering: { + config: [ + { + levels: [ + { + level: 0, + format: LevelFormat.DECIMAL, + text: "%1", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: 260 }, + }, + }, + }, + { + level: 1, + format: LevelFormat.DECIMAL, + text: "%1.%2", + alignment: AlignmentType.START, + style: { + paragraph: { + indent: { left: 1.25 * convertInchesToTwip(0.5), hanging: 1.25 * 260 }, + }, + run: { + bold: true, + size: 18, + font: "Times New Roman", + }, + }, + }, + ], + reference: "my-number-numbering-reference", + }, + ], + }, +}); + +doc.addSection({ + children: [ + new Paragraph({ + text: "How to make cake", + heading: HeadingLevel.HEADING_1, + }), + new Paragraph({ + text: "Step 1 - Add sugar", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "Step 2 - Add wheat", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "Step 2a - Stir the wheat in a circle", + numbering: { + reference: "my-number-numbering-reference", + level: 1, + }, + }), + new Paragraph({ + text: "Step 3 - Put in oven", + numbering: { + reference: "my-number-numbering-reference", + level: 0, + }, + }), + new Paragraph({ + text: "How to make cake", + heading: HeadingLevel.HEADING_1, + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/58-section-types.ts b/demo/58-section-types.ts new file mode 100644 index 0000000000..6c16b44600 --- /dev/null +++ b/demo/58-section-types.ts @@ -0,0 +1,93 @@ +// Usage of different Section Types +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, TextRun, SectionType } from "../build"; + +const doc = new Document(); + +doc.addSection({ + properties: {}, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + ], +}); + +doc.addSection({ + properties: { + type: SectionType.CONTINUOUS, + }, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + ], +}); + +doc.addSection({ + properties: { + type: SectionType.ODD_PAGE, + }, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + ], +}); + +doc.addSection({ + properties: { + type: SectionType.EVEN_PAGE, + }, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + ], +}); + +doc.addSection({ + properties: { + type: SectionType.NEXT_PAGE, + }, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + ], + }), + ], +}); + +Packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/6-page-borders.ts b/demo/6-page-borders.ts index d54aac9a94..e83f18233b 100644 --- a/demo/6-page-borders.ts +++ b/demo/6-page-borders.ts @@ -21,9 +21,9 @@ doc.addSection({ bold: true, }), new TextRun({ - text: "Github is the best", + text: "\tGithub is the best", bold: true, - }).tab(), + }), ], }), new Paragraph({ diff --git a/demo/browser-demo.html b/demo/browser-demo.html index 22c7c821a5..ecd7f47701 100644 --- a/demo/browser-demo.html +++ b/demo/browser-demo.html @@ -12,21 +12,21 @@ - - - - - - - + +
+ + + + + + + + diff --git a/docs/usage/bullet-points.md b/docs/usage/bullet-points.md index 045ec61d1a..159241b3b0 100644 --- a/docs/usage/bullet-points.md +++ b/docs/usage/bullet-points.md @@ -5,12 +5,21 @@ To make a bullet point, simply make a paragraph into a bullet point: ```ts -const text = new TextRun("Bullet points"); -const paragraph = new Paragraph({ - text: "Bullet points", - bullet: { - level: 0, // How deep you want the bullet to me - }, +doc.addSection({ + children: [ + new Paragraph({ + text: "Bullet points", + bullet: { + level: 0 //How deep you want the bullet to be + } + }), + new Paragraph({ + text: "Are awesome", + bullet: { + level: 0 + } + }) + ], }); ``` diff --git a/docs/usage/change-tracking.md b/docs/usage/change-tracking.md new file mode 100644 index 0000000000..a5ca66ebb3 --- /dev/null +++ b/docs/usage/change-tracking.md @@ -0,0 +1,61 @@ +# Change Tracking + +> Instead of adding a `TextRun` into a `Paragraph`, you can also add an `InsertedTextRun` or `DeletedTextRun` where you need to supply an `id`, `author` and `date` for the change. + +```ts +import { Paragraph, TextRun, InsertedTextRun, DeletedTextRun } from "docx"; + +const paragraph = new Paragraph({ + children: [ + new TextRun("This is a simple demo "), + new TextRun({ + text: "on how to " + }), + new InsertedTextRun({ + text: "mark a text as an insertion ", + id: 0, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }), + new DeletedTextRun({ + text: "or a deletion.", + id: 1, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }) + ], +}); +``` + +Note that for a `InsertedTextRun` and `DeletedTextRun`, it is not possible to simply call it with only a text as in `new TextRun("some text")`, since the additonal fields for change tracking need to be provided. Similar to a normal `TextRun` you can add additional text properties. + +```ts +import { Paragraph, TextRun, InsertedTextRun, DeletedTextRun } from "docx"; + +const paragraph = new Paragraph({ + children: [ + new TextRun("This is a simple demo"), + new DeletedTextRun({ + text: "with a deletion.", + color: "red", + bold: true, + size: 24, + id: 0, + author: "Firstname Lastname", + date: "2020-10-06T09:00:00Z", + }) + ], +}); +``` + +In addtion to marking text as inserted or deleted, change tracking can also be added via the document settings. This will enable new changes to be tracked as well. + +```ts +import { Document } from "docx"; + +const doc = new Document({ + features: { + trackRevisions: true, + }, +}); +``` diff --git a/docs/usage/convenience-functions.md b/docs/usage/convenience-functions.md new file mode 100644 index 0000000000..76236ca6c4 --- /dev/null +++ b/docs/usage/convenience-functions.md @@ -0,0 +1,22 @@ +# Convenience functions + +OOXML and this library mainly uses a unit called twentieths of a point or `twip` for short. a twip is a typographical measurement, defined as 1/20 of a typographical point. One twip is 1/1440 inch, or 17.64 μm. This unit is not intuitive for many users, so some functions were created to help + +More info here: https://en.wikipedia.org/wiki/Twip + +## Convert Inches to Twip + +```ts +import { convertInchesToTwip } from "docx"; + +const twip = convertInchesToTwip(1); // returns 1440 +const twip = convertInchesToTwip(0.5); // returns 720 +``` + +## Convert Millimeters to Twip + +```ts +import { convertMillimetersToTwip } from "docx"; + +const twip = convertMillimetersToTwip(50); // returns 2834 +``` diff --git a/docs/usage/document.md b/docs/usage/document.md index bf06d30613..0f1a12486a 100644 --- a/docs/usage/document.md +++ b/docs/usage/document.md @@ -30,6 +30,24 @@ const doc = new docx.Document({ * keywords * lastModifiedBy * revision +* externalStyles +* styles +* numbering +* footnotes +* hyperlinks +* background + +### Change background color of Document + +Set the hex value in the document like so: + +```ts +const doc = new docx.Document({ + background: { + color: "C45911", + }, +}); +``` You can mix and match whatever properties you want, or provide no properties. diff --git a/docs/usage/images.md b/docs/usage/images.md index 4893348cc0..94e75e75a7 100644 --- a/docs/usage/images.md +++ b/docs/usage/images.md @@ -125,6 +125,7 @@ Full options you can pass into `floating` are: | lockAnchor | `boolean` | Optional | | behindDocument | `boolean` | Optional | | layoutInCell | `boolean` | Optional | +| zIndex | `number` | Optional | `HorizontalPositionOptions` are: diff --git a/docs/usage/math.md b/docs/usage/math.md new file mode 100644 index 0000000000..1e8ab4f894 --- /dev/null +++ b/docs/usage/math.md @@ -0,0 +1,265 @@ +# Math + +!> Math requires an understanding of [Sections](usage/sections.md) and [Paragraphs](usage/paragraph.md). + +## Intro + +1. To add math, create a `Math` object +2. Add `MathComponents` inside `Math` +3. `MathComponents` can have nested `MathComponents` inside. e.g. A fraction where the numerator is a square root, and the demoninator as another fraction. More on `MathComponents` below +4. Make sure to add the `Math` object inside a `Paragraph` + +## Example + +```ts +new Math({ + children: [ + new MathRun("2+2"), + new MathFraction({ + numerator: [new MathRun("hi")], + denominator: [new MathRun("2")], + }), + ], +}), +``` + +This will produce: + +

+ clippy the assistant +

+ +## Math Components + +`MathComponents` are the unit sized building blocks of an equation in `docx`. A `MathComponent` takes in more nested `MathComponents` until you reach `MathRun`, which has no children. `MathRun` is similar to a [TextRun](usage/text.md). + +### Math Run + +`MathRun` is the most basic `MathComponent`. + +#### Example + +```ts +new MathRun("2+2"); +``` + +```ts +new MathRun("hello"); +``` + +An example of it being used inside `Math`: + +```ts +new Math({ + children: [ + new MathRun("2"), + new MathRun("+"), + new MathRun("2"), + ], +}), +``` + +### Math Fraction + +`MathFractions` require a `numerator` and a `demoninator`, which are both a list of `MathComponents` + +#### Example + +```ts +new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], +}), +``` + +```ts +new MathFraction({ + numerator: [ + new MathRun("1"), + new MathRadical({ + children: [new MathRun("2")], + }), + ], + denominator: [new MathRun("2")], +}), +``` + +An example of it being used inside `Math`: + +```ts +new Math({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + new MathText("+"), + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + new MathText("= 1"), + ], +}), +``` + +### Sum + +A `MathComponent` for `Σ`. It can take a `superScript` and/or `subScript` as arguments to add `MathComponents` (usually limits) on the top and bottom + +```ts +new MathSum({ + children: [new MathRun("i")], +}), +``` + +```ts +new MathSum({ + children: [ + new MathSuperScript({ + children: [new MathRun("e")], + superScript: [new MathRun("2")], + }) + ], + subScript: [new MathRun("i")], + superScript: [new MathRun("10")], +}), +``` + +### Radicals + +A `MathComponent` for the `√` symbol. Examples include, square root, cube root etc. There is an optional `degree` parameter to specify the number of times the radicand is multiplied by itself. For example, `3` for cube root. + +```ts +new MathRadical({ + children: [new MathRun("2")], +}), +``` + +Cube root example: + +```ts +new MathRadical({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + new MathRun('+ 1'), + ], + degree: [new MathRun("3")], +}), +``` + +### Super Script + +`MathSuperScripts` are the little numbers written to the top right of numbers or variables. It means the exponent or power if written by itself with the number or variable. + +```ts +new MathSuperScript({ + children: [new MathRun("x")], + superScript: [new MathRun("2")], +}), +``` + +An example with cosine: + +```ts +new MathSuperScript({ + children: [new MathRun("cos")], + superScript: [new MathRun("-1")], +}), +``` + +### Sub Script + +`MathSubScripts` are similar to `MathSuperScripts`, except the little number is written below. + +```ts +new MathSubScript({ + children: [new MathRun("F")], + subScript: [new MathRun("n-1")], +}), +``` + +### Sub-Super Script + +`MathSubSuperScripts` are a combination of both `MathSuperScript` and `MathSubScript`. + +```ts +new MathSubSuperScript({ + children: [new MathRun("test")], + superScript: [new MathRun("hello")], + subScript: [new MathRun("world")], +}), +``` + +### Function + +`MathFunctions` are a way of describing what happens to an input variable, in order to get the output result. It takes a `name` parameter to specify the name of the function. + +```ts +new MathFunction({ + name: [ + new MathSuperScript({ + children: [new MathRun("cos")], + superScript: [new MathRun("-1")], + }), + ], + children: [new MathRun("100")], +}), +``` + +### Brackets + +#### Square brackets + +```ts +new MathSquareBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], +}), +``` + +#### Round brackets + +```ts +new MathRoundBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], +}), +``` + +#### Curly brackets + +```ts +new MathCurlyBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], +}), +``` + +#### Angled brackets + +```ts +new MathAngledBrackets({ + children: [ + new MathFraction({ + numerator: [new MathRun("1")], + denominator: [new MathRun("2")], + }), + ], +}), +``` diff --git a/docs/usage/packers.md b/docs/usage/packers.md index e9b3626015..236494bf96 100644 --- a/docs/usage/packers.md +++ b/docs/usage/packers.md @@ -2,11 +2,7 @@ > Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`. -Packers in `version 4` and above are now one single `Packer`. It works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of version 4, this library will not have options to export to PDF. - -## Version 5 - -Packers in `version 5` and above are now static methods on `Packer`. +Packers works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of `version 4+`, this library will not have options to export to PDF. ### Export as Buffer @@ -36,117 +32,3 @@ Packer.toBlob(doc).then((blob) => { saveAs(blob, "example.docx"); }); ``` - -## Version 4 - -The `Packer` in `version 4` requires an instance of `Packer`, so be sure to `new` it. - -### Export as Buffer - -This will return a NodeJS `Buffer`. If this is used in the browser, it will return a `UInt8Array` instead. - -```ts -const packer = new docx.Packer(); - -packer.toBuffer(doc).then((buffer) => { - fs.writeFileSync("My Document.docx", buffer); -}); -``` - -### Export as a `base64` string - -```ts -const packer = new docx.Packer(); - -packer.toBase64String(doc).then((string) => { - console.log(string); -}); -``` - -### Export as Blob - -This is useful if you want to send it as an downloadable in a browser environment. - -```ts -const packer = new docx.Packer(); - -packer.toBlob(doc).then((blob) => { - // saveAs from FileSaver will download the file - saveAs(blob, "example.docx"); -}); -``` - -## Version 3 and below - -### File System Packer - -```ts -const docx = require("docx"); - -const doc = new docx.Document(); -const exporter = new docx.LocalPacker(doc); -exporter.pack("My Document"); -// Word Document is in file system -``` - -### Buffer Packer - -```ts -const docx = require("docx"); - -const doc = new docx.Document(); -const exporter = new docx.BufferPacker(doc); -const buffer = exporter.pack(); -``` - -### Stream Packer - -Creates a `node` `Readable` stream - -```ts -const docx = require("docx"); - -const doc = new docx.Document(); -const exporter = new docx.StreamPacker(doc); -const stream = exporter.pack(); -``` - -### Express Packer - -The old express packer is now deprecated and may disappear soon, so you should upgrade. - -The reason for this is because it means this project needs to know about and use `express`, which for a Word document generator, does not sound right. Seperation of concerns. - -It will still be usable (for now), but it is ill advised. - -I used the express exporter in my [website](http://www.dolan.bio). - -The recommended way is to use the `StreamPacker` and handle the `express` magic outside of the library: - -```ts -const docx = require("docx"); - -const doc = new docx.Document(); -const exporter = new docx.StreamPacker(doc); - -const stream = exporter.pack(); - -// Express' response object -res.attachment("yourfile.xlsx"); -stream.pipe(res); -``` - -where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser. - -### PDF Exporting - -You can export your word document as a PDF file like so: - -```ts -const exporter = new docx.LocalPacker(doc); -exporter.packPdf("My Document"); - -// Express -const exporter = new docx.ExpressPacker(doc, res); -exporter.packPdf("My Document"); -``` diff --git a/docs/usage/paragraph.md b/docs/usage/paragraph.md index f681a09148..ceb4e0aa34 100644 --- a/docs/usage/paragraph.md +++ b/docs/usage/paragraph.md @@ -20,11 +20,7 @@ This method is useful for adding different [text](text.md) with different styles ```ts const paragraph = new Paragraph({ - children: [ - new TextRun("Lorem Ipsum Foo Bar"), - new TextRun("Hello World"), - new SymbolRun("F071"), - ], + children: [new TextRun("Lorem Ipsum Foo Bar"), new TextRun("Hello World"), new SymbolRun("F071")], }); ``` @@ -60,27 +56,27 @@ doc.addSection({ This is the list of options for a paragraph. A detailed explanation is below: -| Property | Type | Mandatory? | Possible Values | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | -| [text](#text) | `string` | Optional | | -| [heading](#heading) | `HeadingLevel` | Optional | `HEADING_1`, `HEADING_2`, `HEADING_3`, `HEADING_4`, `HEADING_5`, `HEADING_6`, `TITLE` | -| [border](#border) | `IBorderOptions` | Optional | `top`, `bottom`, `left`, `right`. Each of these are of type IBorderPropertyOptions. Click here for Example | -| [spacing](#spacing) | `ISpacingProperties` | Optional | See below for ISpacingProperties | +| Property | Type | Mandatory? | Possible Values | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | +| [text](#text) | `string` | Optional | | +| [heading](#heading) | `HeadingLevel` | Optional | `HEADING_1`, `HEADING_2`, `HEADING_3`, `HEADING_4`, `HEADING_5`, `HEADING_6`, `TITLE` | +| [border](#border) | `IBorderOptions` | Optional | `top`, `bottom`, `left`, `right`. Each of these are of type IBorderPropertyOptions. Click here for Example | +| [spacing](#spacing) | `ISpacingProperties` | Optional | See below for ISpacingProperties | | [outlineLevel](#outline-level) | `number` | Optional | | -| alignment | `AlignmentType` | Optional | | -| heading | `HeadingLevel` | Optional | | -| bidirectional | `boolean` | Optional | | -| thematicBreak | `boolean` | Optional | | -| pageBreakBefore | `boolean` | Optional | | -| contextualSpacing | `boolean` | Optional | | -| indent | `IIndentAttributesProperties` | Optional | | -| keepLines | `boolean` | Optional | | -| keepNext | `boolean` | Optional | | -| children | `(TextRun or PictureRun or Hyperlink)[]` | Optional | | -| style | `string` | Optional | | -| tabStop | `{ left?: ITabStopOptions; right?: ITabStopOptions; maxRight?: { leader: LeaderType; }; center?: ITabStopOptions }` | Optional | | -| bullet | `{ level: number }` | Optional | | -| numbering | `{ num: Num; level: number; custom?: boolean }` | Optional | | +| alignment | `AlignmentType` | Optional | | +| heading | `HeadingLevel` | Optional | | +| bidirectional | `boolean` | Optional | | +| thematicBreak | `boolean` | Optional | | +| pageBreakBefore | `boolean` | Optional | | +| contextualSpacing | `boolean` | Optional | | +| indent | `IIndentAttributesProperties` | Optional | | +| keepLines | `boolean` | Optional | | +| keepNext | `boolean` | Optional | | +| children | `(TextRun or PictureRun or Hyperlink)[]` | Optional | | +| style | `string` | Optional | | +| tabStop | `{ left?: ITabStopOptions; right?: ITabStopOptions; maxRight?: { leader: LeaderType; }; center?: ITabStopOptions }` | Optional | | +| bullet | `{ level: number }` | Optional | | +| numbering | `{ num: ConcreteNumbering; level: number; custom?: boolean }` | Optional | | ## Text @@ -146,6 +142,21 @@ const paragraph = new Paragraph({ }); ``` +## Shading + +Add color to an entire paragraph block + +```ts +const paragraph = new Paragraph({ + text: "shading", + shading: { + type: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "00FFFF", + fill: "FF0000", + }, +}); +``` + ## Spacing Adding spacing between paragraphs @@ -252,10 +263,7 @@ To move to a new page (insert a page break): ```ts const paragraph = new docx.Paragraph({ - children: [ - new TextRun("Amazing Heading"), - new PageBreak(), - ] + children: [new TextRun("Amazing Heading"), new PageBreak()], }); ``` diff --git a/docs/usage/sections.md b/docs/usage/sections.md index 5b6d4e9c74..daabb02294 100644 --- a/docs/usage/sections.md +++ b/docs/usage/sections.md @@ -19,3 +19,30 @@ doc.addSection({ ], }); ``` + +## Properties + +You can specify additional properties to the section, by providing a `properties` attribute. + +### Section Type + +Setting the section type determines how the contents of the section will be placed relative to the previous section. E.g., There are five different types: + +- `CONTINUOUS` +- `EVEN_PAGE` +- `NEXT_COLUMN` +- `NEXT_PAGE` +- `ODD_PAGE` + +```ts +doc.addSection({ + properties: { + type: SectionType.CONTINUOUS, + } + children: [ + new Paragraph({ + children: [new TextRun("Hello World")], + }), + ], +}); +``` diff --git a/docs/usage/styling-with-js.md b/docs/usage/styling-with-js.md index 26d294c942..0dafac2904 100644 --- a/docs/usage/styling-with-js.md +++ b/docs/usage/styling-with-js.md @@ -22,10 +22,11 @@ const name = new TextRun({ ### Run formatting - `bold`, `italics`, `smallCaps`, `allCaps`, `strike`, `doubleStrike`, `subScript`, `superScript`: Set the formatting property to true -- `underline(style="single", color=null)`: Set the underline style and color +- `underline({type="single", color=null})`: Set the underline style and color +- `emphasisMark({type="dot"})`: Set the emphasis mark style - `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`) - `size(halfPts)`: Set the font size, measured in half-points -- `font(name)`: Set the run's font +- `font(name)` or `font({ascii, cs, eastAsia, hAnsi, hint})`: Set the run's font - `style(name)`: Apply a named run style - `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs) diff --git a/docs/usage/tab-stops.md b/docs/usage/tab-stops.md index 5c7a99da42..1a3d1e3b2e 100644 --- a/docs/usage/tab-stops.md +++ b/docs/usage/tab-stops.md @@ -12,7 +12,7 @@ Simply call the relevant methods on the paragraph listed below. Then just add a ```ts const paragraph = new Paragraph({ - children: [new TextRun("Hey everyone").bold(), new TextRun("11th November 1999").tab()], + children: [new TextRun("Hey everyone").bold(), new TextRun(\t"11th November 1999")], tabStops: [ { type: TabStopType.RIGHT, @@ -26,7 +26,7 @@ The example above will create a left aligned text, and a right aligned text on t ```ts const paragraph = new Paragraph({ - children: [new TextRun("Second tab stop here I come!").tab().tab()], + children: [new TextRun("Second tab stop here I come!")], tabStops: [ { type: TabStopType.RIGHT, @@ -46,7 +46,7 @@ You can add multiple tab stops of the same `type` too. ```ts const paragraph = new Paragraph({ - children: [new TextRun("Multiple tab stops!").tab().tab()], + children: [new TextRun("Multiple tab stops!")], tabStops: [ { type: TabStopType.RIGHT, diff --git a/docs/usage/tables.md b/docs/usage/tables.md index a8e41de58a..637efa2977 100644 --- a/docs/usage/tables.md +++ b/docs/usage/tables.md @@ -51,19 +51,6 @@ const table = new Table({ }); ``` -### Pagination - -#### Prevent row pagination - -To prevent breaking contents of a row across multiple pages, call `cantSplit`: - -```ts -const table = new Table({ - rows: [], - cantSplit: true, -}); -``` - ## Table Row A table consists of multiple `table rows`. Table rows have a list of `children` which accepts a list of `table cells` explained below. You can create a simple `table row` like so: @@ -103,7 +90,7 @@ Here is a list of options you can add to the `table row`: | children | `Array` | Required | | cantSplit | `boolean` | Optional | | tableHeader | `boolean` | Optional | -| height | `{ value: number, rule: HeightRule }` | Optional | +| height | `{ height: number, rule: HeightRule }` | Optional | ### Repeat row @@ -116,6 +103,19 @@ const row = new TableRow({ }); ``` +### Pagination + +#### Prevent row pagination + +To prevent breaking contents of a row across multiple pages, call `cantSplit`: + +```ts +const row = new Row({ + ..., + cantSplit: true, +}); +``` + ## Table Cells Cells need to be added in the `table row`, you can create a table cell like: @@ -326,6 +326,17 @@ const cell = new TableCell({ }); ``` +### Visual Right to Left Table + +It is possible to reverse how the cells of the table are displayed. The table direction. More info here: https://superuser.com/questions/996912/how-to-change-a-table-direction-in-microsoft-word + +```ts +const table = new Table({ + visuallyRightToLeft: true, +}); +``` + + ## Examples [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/4-basic-table.ts ':include') diff --git a/docs/usage/text.md b/docs/usage/text.md index 6cbd9da224..0b7b88686b 100644 --- a/docs/usage/text.md +++ b/docs/usage/text.md @@ -68,40 +68,87 @@ const text = new TextRun({ }); ``` +### Emphasis Mark + +```ts +const text = new TextRun({ + text: "and then emphasis mark", + emphasisMark: {}, +}); +``` + +### Shading and Highlighting + +```ts +const text = new TextRun({ + text: "shading", + shading: { + type: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "00FFFF", + fill: "FF0000", + }, +}); +``` + +```ts +const text = new TextRun({ + text: "highlighting", + highlight: "yellow", +}); +``` + ### Strike through ```ts -text.strike(); +const text = new TextRun({ + text: "strike", + strike: true, +}); ``` ### Double strike through ```ts -text.doubleStrike(); +const text = new TextRun({ + text: "doubleStrike", + doubleStrike: true, +}); ``` ### Superscript ```ts -text.superScript(); +const text = new TextRun({ + text: "superScript", + superScript: true, +}); ``` ### Subscript ```ts -text.subScript(); +const text = new TextRun({ + text: "subScript", + subScript: true, +}); ``` ### All Capitals ```ts -text.allCaps(); +const text = new TextRun({ + text: "allCaps", + allCaps: true, +}); ``` ### Small Capitals ```ts -text.smallCaps(); +const text = new TextRun({ + text: "smallCaps", + smallCaps: true, +}); ``` ## Break @@ -109,13 +156,17 @@ text.smallCaps(); Sometimes you would want to put text underneath another line of text but inside the same paragraph. ```ts -text.break(); +const text = new TextRun({ + text: "break", + break: 1, +}); ``` -## Chaining - -What if you want to create a paragraph which is **_bold_** and **_italic_**? +Adding two breaks: ```ts -paragraph.bold().italics(); +const text = new TextRun({ + text: "break", + break: 2, +}); ``` diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..183d28b7b3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9214 @@ +{ + "name": "docx", + "version": "5.5.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/core": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.0.tgz", + "integrity": "sha512-mkLq8nwaXmDtFmRkQ8ED/eA2CnVw4zr7dCztKalZXBvdK5EeNUAesrrwUqjQEzFgomJssayzB0aqlOsP1vGLqg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.0", + "@babel/types": "^7.11.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", + "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, + "@babel/parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, + "@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", + "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + }, + "dependencies": { + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + } + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + }, + "dependencies": { + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + } + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/bluebird": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.33.tgz", + "integrity": "sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==", + "dev": true + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "@types/chai": { + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.15.tgz", + "integrity": "sha512-rYff6FI+ZTKAPkJUoyz7Udq3GaoDZnxYDEvdEdFZASiA7PoErltHezDishqQiSDWrGxvxmplH304jyzQmjp0AQ==", + "dev": true + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/jszip": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/jszip/-/jszip-3.4.1.tgz", + "integrity": "sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A==", + "requires": { + "jszip": "*" + } + }, + "@types/mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-NysN+bNqj6E0Hv4CTGWSlPzMW6vTKjDpOteycDkV4IWBsO+PU48JonrPzV9ODjiI2XrjmA05KInLgF5ivZ/YGQ==", + "dev": true + }, + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==" + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/request-promise": { + "version": "4.1.47", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.47.tgz", + "integrity": "sha512-eRSZhAS8SMsrWOM8vbhxFGVZhTbWSJvaRKyufJTdIf4gscUouQvOBlfotPSPHbMR3S7kfkyKbhb1SWPmQdy3KQ==", + "dev": true, + "requires": { + "@types/bluebird": "*", + "@types/request": "*" + } + }, + "@types/shortid": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", + "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=", + "dev": true + }, + "@types/sinon": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.10.tgz", + "integrity": "sha512-/faDC0erR06wMdybwI/uR8wEKV/E83T0k4sepIpB7gXuy2gzx2xiOjmztq6a2Y6rIGJ04D+6UU0VBmWy+4HEMA==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", + "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", + "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "@types/webpack": { + "version": "4.41.26", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz", + "integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "^4.0.3" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "awesome-typescript-loader": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-3.5.0.tgz", + "integrity": "sha512-qzgm9SEvodVkSi9QY7Me1/rujg+YBNMjayNSAyzNghwTEez++gXoPCwMvpbHRG7wrOkDCiF6dquvv9ESmUBAuw==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "enhanced-resolve": "3.3.0", + "loader-utils": "^1.1.0", + "lodash": "^4.17.4", + "micromatch": "^3.0.3", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.3" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "clipboard": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", + "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "dev": true, + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cp-file": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", + "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "dev": true, + "optional": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "docsify": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.12.0.tgz", + "integrity": "sha512-oLr48dLeJ8sTVQfL8HLFqd2sPPG8DNAOvYAXXJQr/+/K9uC2KDhoeu+GGj5U2uFGR5czF3oLvqNBxhEElg1wGw==", + "dev": true, + "requires": { + "dompurify": "^2.2.6", + "marked": "^1.2.9", + "medium-zoom": "^1.0.6", + "opencollective-postinstall": "^2.0.2", + "prismjs": "^1.23.0", + "strip-indent": "^3.0.0", + "tinydate": "^1.3.0", + "tweezer.js": "^1.4.0" + }, + "dependencies": { + "dompurify": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", + "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==", + "dev": true + }, + "marked": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", + "dev": true + }, + "prismjs": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", + "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", + "dev": true, + "requires": { + "clipboard": "^2.0.0" + } + } + } + }, + "docsify-cli": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/docsify-cli/-/docsify-cli-4.4.2.tgz", + "integrity": "sha512-iCTRyKjjNiSroo5cgVkb/C86PsUEEsVV30PXp5GkzbcMG+mMxzBPmJ/8xukTLoeaQddEsSeSWW376eC2t4KQJw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "connect": "^3.6.0", + "connect-livereload": "^0.6.0", + "cp-file": "^7.0.0", + "docsify": "^4.10.2", + "docsify-server-renderer": ">=4", + "enquirer": "^2.3.6", + "fs-extra": "^8.1.0", + "get-port": "^5.0.0", + "livereload": "^0.9.1", + "lru-cache": "^5.1.1", + "open": "^6.4.0", + "serve-static": "^1.12.1", + "update-notifier": "^4.1.0", + "yargonaut": "^1.1.2", + "yargs": "^14.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "yargs-parser": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "docsify-server-renderer": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.11.6.tgz", + "integrity": "sha512-IAEM+kKsDfo1qnrEdaBH5pCQFjAWA7B7jWWmfCKzDA/BPcHO+zCR4++Mw/NPR/huJKU58AzuGtEJ/NhF/l0Y6Q==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "docsify": "^4.11.4", + "dompurify": "^2.0.8", + "node-fetch": "^2.6.0", + "resolve-pathname": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "dompurify": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.2.tgz", + "integrity": "sha512-BsGR4nDLaC5CNBnyT5I+d5pOeaoWvgVeg6Gq/aqmKYWMPR07131u60I80BvExLAJ0FQEIBQ1BTicw+C5+jOyrg==", + "dev": true + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz", + "integrity": "sha512-2qbxE7ek3YxPJ1ML6V+satHkzHpJQKWkRHmRx6mfAoW59yP8YH8BFplbegSP+u2hBd6B6KCOpvJQ3dZAP+hkpg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.5" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "figlet": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.0.tgz", + "integrity": "sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww==", + "dev": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fromentries": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.1.tgz", + "integrity": "sha512-Xu2Qh8yqYuDhQGOhD5iJGninErSfI9A3FrriD3tjUgV5VbJFeH8vfgZ9HnC6jWN80QDVNQK5vmxRAmEAp7Mevw==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz", + "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", + "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true, + "optional": true + } + } + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", + "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "dev": true, + "requires": { + "ini": "^1.3.5" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dev": true, + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + }, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + } + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-instrumenter-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz", + "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", + "dev": true, + "requires": { + "convert-source-map": "^1.5.0", + "istanbul-lib-instrument": "^1.7.3", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz", + "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, + "livereload": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.1.tgz", + "integrity": "sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==", + "dev": true, + "requires": { + "chokidar": "^3.3.0", + "livereload-js": "^3.1.0", + "opts": ">= 1.2.0", + "ws": "^6.2.1" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "livereload-js": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.3.1.tgz", + "integrity": "sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "marked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz", + "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==", + "dev": true + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "medium-zoom": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.6.tgz", + "integrity": "sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg==", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "mocha-webpack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mocha-webpack/-/mocha-webpack-1.1.0.tgz", + "integrity": "sha512-brmE0tR6G5JbEzZXspJmF/uZm2J/YM/69M3VS6ND76i6wXbebFpE+bQDaehilK8CZanNSsTCcqTTLh1PZuRKJw==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "chalk": "^2.3.0", + "chokidar": "^1.6.1", + "glob-parent": "^3.1.0", + "globby": "^6.1.0", + "interpret": "^1.0.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "lodash": "^4.3.0", + "memory-fs": "^0.4.1", + "nodent-runtime": "^3.0.3", + "normalize-path": "^2.0.1", + "progress": "^2.0.0", + "source-map-support": "^0.5.0", + "strip-ansi": "^4.0.0", + "toposort": "^1.0.0", + "yargs": "^4.8.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "ncp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", + "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nise": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "nodent-runtime": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/nodent-runtime/-/nodent-runtime-3.2.1.tgz", + "integrity": "sha512-7Ws63oC+215smeKJQCxzrK21VFVlCFBkwl0MOObt0HOpVQXs3u483sAmtkF33nNqZ5rSOQjB76fgyPBmAUrtCA==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onigasm": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", + "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", + "dev": true, + "requires": { + "lru-cache": "^5.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true + }, + "opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", + "dev": true + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" + }, + "parent-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", + "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=", + "dev": true + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "pre-commit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "spawn-sync": "^1.0.15", + "which": "1.2.x" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prompt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.1.0.tgz", + "integrity": "sha512-ec1vUPXCplDBDUVD8uPa3XGA+OzLrO40Vxv3F1uxoiZGkZhdctlK2JotcHq5X6ExjocDOGwGdCSXloGNyU5L1Q==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "read": "1.0.x", + "revalidator": "0.1.x", + "utile": "0.3.x", + "winston": "2.x" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-in-file": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-3.4.4.tgz", + "integrity": "sha512-ehq0dFsxSpfPiPLBU5kli38Ud8bZL0CQKG8WQVbvhmyilXaMJ8y4LtDZs/K3MD8C0+rHbsfW8c9r2bUEy0B/6Q==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "glob": "^7.1.3", + "yargs": "^13.2.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shiki": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.2.tgz", + "integrity": "sha512-BjUCxVbxMnvjs8jC4b+BQ808vwjJ9Q8NtLqPwXShZ307HdXiDFYP968ORSVfaTNNSWYDBYdMnVKJ0fYNsoZUBA==", + "dev": true, + "requires": { + "onigasm": "^2.2.5", + "vscode-textmate": "^5.2.0" + } + }, + "shortid": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", + "requires": { + "nanoid": "^2.1.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", + "integrity": "sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/samsam": "^5.3.1", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tapable": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", + "dev": true + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "optional": true + }, + "tinydate": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", + "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "tslint-immutable": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tslint-immutable/-/tslint-immutable-6.0.1.tgz", + "integrity": "sha512-3GQ6HffN64gLmT/N1YzyVMqyf6uBjMvhNaevK8B0K01/QC0OU5AQZrH4TjMHo1IdG3JpqsZvuRy9IW1LA3zjwA==", + "dev": true, + "requires": { + "tsutils": "^2.28.0 || ^3.0.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "tweezer.js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/tweezer.js/-/tweezer.js-1.5.0.tgz", + "integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ==", + "dev": true + }, + "type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz", + "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==", + "dev": true + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typedoc": { + "version": "0.20.29", + "resolved": "http://registry.npmjs.org/typedoc/-/typedoc-0.20.29.tgz", + "integrity": "sha512-IyzrbtwNAXtylUJn41FbopQsNSQ1jcM6lUhDL/REOFo31G3Q9fsniZUQP+tIcTX5JaCntRdw3PTMZTQPV52low==", + "dev": true, + "requires": { + "colors": "^1.4.0", + "fs-extra": "^9.1.0", + "handlebars": "^4.7.7", + "lodash": "^4.17.21", + "lunr": "^2.3.9", + "marked": "^2.0.1", + "minimatch": "^3.0.0", + "progress": "^2.0.3", + "shelljs": "^0.8.4", + "shiki": "^0.9.2", + "typedoc-default-themes": "^0.12.8" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.8.tgz", + "integrity": "sha512-tyjyDTKy/JLnBSwvhoqd99VIjrP33SdOtwcMD32b+OqnrjZWe8HmZECbfBoacqoxjHd58gfeNw6wA7uvqWFa4w==", + "dev": true + }, + "typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "dev": true + }, + "uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-TWYSWa9T2pPN4DIJYbU9oAjQx+5qdV5RUDxwARg8fmJZrD/V27Zj0JngW5xg1DFz42G0uDYl2XhzF6alSzD62w==", + "dev": true, + "optional": true + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "^0.5.6", + "uglify-js": "^2.8.29", + "webpack-sources": "^1.0.1" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utile": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz", + "integrity": "sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo=", + "dev": true, + "requires": { + "async": "~0.9.0", + "deep-equal": "~0.2.1", + "i": "0.3.x", + "mkdirp": "0.x.x", + "ncp": "1.0.x", + "rimraf": "2.x.x" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true + }, + "vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "chokidar": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "webpack": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", + "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==", + "dev": true, + "requires": { + "acorn": "^5.0.0", + "acorn-dynamic-import": "^2.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "async": "^2.1.2", + "enhanced-resolve": "^3.4.0", + "escope": "^3.6.0", + "interpret": "^1.0.0", + "json-loader": "^0.5.4", + "json5": "^0.5.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "mkdirp": "~0.5.0", + "node-libs-browser": "^2.0.0", + "source-map": "^0.5.3", + "supports-color": "^4.2.1", + "tapable": "^0.2.7", + "uglifyjs-webpack-plugin": "^0.4.6", + "watchpack": "^1.4.0", + "webpack-sources": "^1.0.1", + "yargs": "^8.0.2" + }, + "dependencies": { + "ajv": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", + "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "dev": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargonaut": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz", + "integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "figlet": "^1.1.1", + "parent-require": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 1fbe0f4f2f..0817dbbc0b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "docx", - "version": "5.0.0-rc7", - "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", + "version": "5.5.0", + "description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.", "main": "build/index.js", "scripts": { "pretest": "rimraf ./build", @@ -50,7 +50,9 @@ "types": "./build/index.d.ts", "dependencies": { "@types/jszip": "^3.1.4", + "@types/node": "^14.0.5", "jszip": "^3.1.5", + "shortid": "^2.2.15", "xml": "^1.0.1", "xml-js": "^1.6.8" }, @@ -61,10 +63,11 @@ }, "homepage": "https://github.com/dolanmiu/docx#readme", "devDependencies": { - "@types/chai": "^3.4.35", - "@types/mocha": "^2.2.39", + "@types/chai": "^4.2.15", + "@types/mocha": "^8.0.0", "@types/request-promise": "^4.1.42", - "@types/sinon": "^4.3.1", + "@types/shortid": "0.0.29", + "@types/sinon": "^9.0.4", "@types/webpack": "^4.4.24", "awesome-typescript-loader": "^3.4.1", "chai": "^3.5.0", @@ -74,24 +77,24 @@ "jszip": "^3.1.5", "mocha": "^5.2.0", "mocha-webpack": "^1.0.1", - "nyc": "^13.1.0", + "nyc": "^15.1.0", "pre-commit": "^1.2.2", - "prettier": "^1.15.2", + "prettier": "^2.1.2", "prompt": "^1.0.0", "replace-in-file": "^3.1.0", "request": "^2.88.0", "request-promise": "^4.2.2", - "rimraf": "^2.5.2", - "shelljs": "^0.7.7", - "sinon": "^5.0.7", - "ts-node": "^7.0.1", - "tslint": "^5.11.0", - "tslint-immutable": "^4.9.0", - "typedoc": "^0.11.1", - "typescript": "2.9.2", + "rimraf": "^3.0.2", + "shelljs": "^0.8.4", + "sinon": "^9.0.2", + "ts-node": "^9.0.0", + "tslint": "^6.1.3", + "tslint-immutable": "^6.0.1", + "typedoc": "^0.20.29", + "typescript": "4.2.3", "webpack": "^3.10.0" }, "engines": { - "node": ">=8" + "node": ">=10" } } diff --git a/src/convenience-functions.spec.ts b/src/convenience-functions.spec.ts new file mode 100644 index 0000000000..3333fdd2d0 --- /dev/null +++ b/src/convenience-functions.spec.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import { convertInchesToTwip, convertMillimetersToTwip } from "./convenience-functions"; + +describe("Utility", () => { + describe("#convertMillimetersToTwip", () => { + it("should call the underlying header's addChildElement for Paragraph", () => { + expect(convertMillimetersToTwip(1000)).to.equal(56692); + }); + }); + + describe("#convertInchesToTwip", () => { + it("should call the underlying header's addChildElement", () => { + expect(convertInchesToTwip(1)).to.equal(1440); + expect(convertInchesToTwip(0.5)).to.equal(720); + expect(convertInchesToTwip(0.25)).to.equal(360); + }); + }); +}); diff --git a/src/convenience-functions.ts b/src/convenience-functions.ts new file mode 100644 index 0000000000..6fe110b72b --- /dev/null +++ b/src/convenience-functions.ts @@ -0,0 +1,8 @@ +// Twip - twentieths of a point +export const convertMillimetersToTwip = (millimeters: number): number => { + return Math.floor((millimeters / 25.4) * 72 * 20); +}; + +export const convertInchesToTwip = (inches: number): number => { + return Math.floor(inches * 72 * 20); +}; diff --git a/src/export/formatter.ts b/src/export/formatter.ts index 0a28070d13..a91702212e 100644 --- a/src/export/formatter.ts +++ b/src/export/formatter.ts @@ -1,8 +1,9 @@ +import { IViewWrapper } from "file/document-wrapper"; import { BaseXmlComponent, IXmlableObject } from "file/xml-components"; export class Formatter { - public format(input: BaseXmlComponent): IXmlableObject { - const output = input.prepForXml(); + public format(input: BaseXmlComponent, file?: IViewWrapper): IXmlableObject { + const output = input.prepForXml(file); if (output) { return output; diff --git a/src/export/packer/image-replacer.ts b/src/export/packer/image-replacer.ts index 9cb3f950d5..0d2e2854f8 100644 --- a/src/export/packer/image-replacer.ts +++ b/src/export/packer/image-replacer.ts @@ -5,7 +5,7 @@ export class ImageReplacer { let currentXmlData = xmlData; mediaData.forEach((image, i) => { - currentXmlData = currentXmlData.replace(`{${image.fileName}}`, (offset + i).toString()); + currentXmlData = currentXmlData.replace(new RegExp(`{${image.fileName}}`, "g"), (offset + i).toString()); }); return currentXmlData; diff --git a/src/export/packer/next-compiler.spec.ts b/src/export/packer/next-compiler.spec.ts index 7c48569793..d0dfbf08ae 100644 --- a/src/export/packer/next-compiler.spec.ts +++ b/src/export/packer/next-compiler.spec.ts @@ -16,26 +16,28 @@ describe("Compiler", () => { }); describe("#compile()", () => { - it("should pack all the content", async function() { + it("should pack all the content", async function () { this.timeout(99999999); const zipFile = compiler.compile(file); const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); expect(fileNames).is.an.instanceof(Array); - expect(fileNames).has.length(14); + expect(fileNames).has.length(16); expect(fileNames).to.include("word/document.xml"); expect(fileNames).to.include("word/styles.xml"); expect(fileNames).to.include("docProps/core.xml"); + expect(fileNames).to.include("docProps/custom.xml"); expect(fileNames).to.include("docProps/app.xml"); expect(fileNames).to.include("word/numbering.xml"); expect(fileNames).to.include("word/footnotes.xml"); + expect(fileNames).to.include("word/_rels/footnotes.xml.rels"); expect(fileNames).to.include("word/settings.xml"); expect(fileNames).to.include("word/_rels/document.xml.rels"); expect(fileNames).to.include("[Content_Types].xml"); expect(fileNames).to.include("_rels/.rels"); }); - it("should pack all additional headers and footers", async function() { + it("should pack all additional headers and footers", async function () { file.addSection({ headers: { default: new Header(), @@ -62,7 +64,7 @@ describe("Compiler", () => { const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); expect(fileNames).is.an.instanceof(Array); - expect(fileNames).has.length(22); + expect(fileNames).has.length(24); expect(fileNames).to.include("word/header1.xml"); expect(fileNames).to.include("word/_rels/header1.xml.rels"); @@ -88,7 +90,7 @@ describe("Compiler", () => { const spy = sinon.spy(compiler["formatter"], "format"); compiler.compile(file); - expect(spy.callCount).to.equal(10); + expect(spy.callCount).to.equal(12); }); }); }); diff --git a/src/export/packer/next-compiler.ts b/src/export/packer/next-compiler.ts index 6a3e752098..e5f66c8d96 100644 --- a/src/export/packer/next-compiler.ts +++ b/src/export/packer/next-compiler.ts @@ -4,6 +4,7 @@ import * as xml from "xml"; import { File } from "file"; import { Formatter } from "../formatter"; import { ImageReplacer } from "./image-replacer"; +import { NumberingReplacer } from "./numbering-replacer"; interface IXmlifyedFile { readonly data: string; @@ -22,18 +23,22 @@ interface IXmlifyedFileMapping { readonly HeaderRelationships: IXmlifyedFile[]; readonly FooterRelationships: IXmlifyedFile[]; readonly ContentTypes: IXmlifyedFile; + readonly CustomProperties: IXmlifyedFile; readonly AppProperties: IXmlifyedFile; readonly FootNotes: IXmlifyedFile; + readonly FootNotesRelationships: IXmlifyedFile; readonly Settings: IXmlifyedFile; } export class Compiler { private readonly formatter: Formatter; private readonly imageReplacer: ImageReplacer; + private readonly numberingReplacer: NumberingReplacer; constructor() { this.formatter = new Formatter(); this.imageReplacer = new ImageReplacer(); + this.numberingReplacer = new NumberingReplacer(); } public compile(file: File, prettifyXml?: boolean): JSZip { @@ -66,40 +71,41 @@ export class Compiler { private xmlifyFile(file: File, prettify?: boolean): IXmlifyedFileMapping { file.verifyUpdateFields(); - const documentRelationshipCount = file.DocumentRelationships.RelationshipCount + 1; + const documentRelationshipCount = file.Document.Relationships.RelationshipCount + 1; - const documentXmlData = xml(this.formatter.format(file.Document), prettify); + const documentXmlData = xml(this.formatter.format(file.Document.View, file.Document), prettify); const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media); return { Relationships: { data: (() => { documentMediaDatas.forEach((mediaData, i) => { - file.DocumentRelationships.createRelationship( + file.Document.Relationships.createRelationship( documentRelationshipCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${mediaData.fileName}`, ); }); - return xml(this.formatter.format(file.DocumentRelationships), prettify); + return xml(this.formatter.format(file.Document.Relationships, file.Document), prettify); })(), path: "word/_rels/document.xml.rels", }, Document: { data: (() => { const xmlData = this.imageReplacer.replace(documentXmlData, documentMediaDatas, documentRelationshipCount); + const referenedXmlData = this.numberingReplacer.replace(xmlData, file.Numbering.ConcreteNumbering); - return xmlData; + return referenedXmlData; })(), path: "word/document.xml", }, Styles: { - data: xml(this.formatter.format(file.Styles), prettify), + data: xml(this.formatter.format(file.Styles, file.Document), prettify), path: "word/styles.xml", }, Properties: { - data: xml(this.formatter.format(file.CoreProperties), { + data: xml(this.formatter.format(file.CoreProperties, file.Document), { declaration: { standalone: "yes", encoding: "UTF-8", @@ -108,15 +114,15 @@ export class Compiler { path: "docProps/core.xml", }, Numbering: { - data: xml(this.formatter.format(file.Numbering), prettify), + data: xml(this.formatter.format(file.Numbering, file.Document), prettify), path: "word/numbering.xml", }, FileRelationships: { - data: xml(this.formatter.format(file.FileRelationships), prettify), + data: xml(this.formatter.format(file.FileRelationships, file.Document), prettify), path: "_rels/.rels", }, HeaderRelationships: file.Headers.map((headerWrapper, index) => { - const xmlData = xml(this.formatter.format(headerWrapper.Header), prettify); + const xmlData = xml(this.formatter.format(headerWrapper.View, headerWrapper), prettify); const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media); mediaDatas.forEach((mediaData, i) => { @@ -128,12 +134,12 @@ export class Compiler { }); return { - data: xml(this.formatter.format(headerWrapper.Relationships), prettify), + data: xml(this.formatter.format(headerWrapper.Relationships, headerWrapper), prettify), path: `word/_rels/header${index + 1}.xml.rels`, }; }), FooterRelationships: file.Footers.map((footerWrapper, index) => { - const xmlData = xml(this.formatter.format(footerWrapper.Footer), prettify); + const xmlData = xml(this.formatter.format(footerWrapper.View, footerWrapper), prettify); const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media); mediaDatas.forEach((mediaData, i) => { @@ -145,12 +151,12 @@ export class Compiler { }); return { - data: xml(this.formatter.format(footerWrapper.Relationships), prettify), + data: xml(this.formatter.format(footerWrapper.Relationships, footerWrapper), prettify), path: `word/_rels/footer${index + 1}.xml.rels`, }; }), Headers: file.Headers.map((headerWrapper, index) => { - const tempXmlData = xml(this.formatter.format(headerWrapper.Header), prettify); + const tempXmlData = xml(this.formatter.format(headerWrapper.View, headerWrapper), prettify); const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media); // TODO: 0 needs to be changed when headers get relationships of their own const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0); @@ -161,7 +167,7 @@ export class Compiler { }; }), Footers: file.Footers.map((footerWrapper, index) => { - const tempXmlData = xml(this.formatter.format(footerWrapper.Footer), prettify); + const tempXmlData = xml(this.formatter.format(footerWrapper.View, footerWrapper), prettify); const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media); // TODO: 0 needs to be changed when headers get relationships of their own const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0); @@ -172,19 +178,27 @@ export class Compiler { }; }), ContentTypes: { - data: xml(this.formatter.format(file.ContentTypes), prettify), + data: xml(this.formatter.format(file.ContentTypes, file.Document), prettify), path: "[Content_Types].xml", }, + CustomProperties: { + data: xml(this.formatter.format(file.CustomProperties, file.Document), prettify), + path: "docProps/custom.xml", + }, AppProperties: { - data: xml(this.formatter.format(file.AppProperties), prettify), + data: xml(this.formatter.format(file.AppProperties, file.Document), prettify), path: "docProps/app.xml", }, FootNotes: { - data: xml(this.formatter.format(file.FootNotes), prettify), + data: xml(this.formatter.format(file.FootNotes.View, file.FootNotes), prettify), path: "word/footnotes.xml", }, + FootNotesRelationships: { + data: xml(this.formatter.format(file.FootNotes.Relationships, file.FootNotes), prettify), + path: "word/_rels/footnotes.xml.rels", + }, Settings: { - data: xml(this.formatter.format(file.Settings), prettify), + data: xml(this.formatter.format(file.Settings, file.Document), prettify), path: "word/settings.xml", }, }; diff --git a/src/export/packer/numbering-replacer.ts b/src/export/packer/numbering-replacer.ts new file mode 100644 index 0000000000..4ac5dcbf1d --- /dev/null +++ b/src/export/packer/numbering-replacer.ts @@ -0,0 +1,17 @@ +import { ConcreteNumbering } from "file"; + +export class NumberingReplacer { + public replace(xmlData: string, concreteNumberings: ConcreteNumbering[]): string { + let currentXmlData = xmlData; + + for (const concreteNumbering of concreteNumberings) { + if (!concreteNumbering.reference) { + continue; + } + + currentXmlData = currentXmlData.replace(new RegExp(`{${concreteNumbering.reference}}`, "g"), concreteNumbering.id.toString()); + } + + return currentXmlData; + } +} diff --git a/src/export/packer/packer.spec.ts b/src/export/packer/packer.spec.ts index 8235649f15..18ae459b49 100644 --- a/src/export/packer/packer.spec.ts +++ b/src/export/packer/packer.spec.ts @@ -36,7 +36,7 @@ describe("Packer", () => { }); describe("#toBuffer()", () => { - it("should create a standard docx file", async function() { + it("should create a standard docx file", async function () { this.timeout(99999999); const buffer = await Packer.toBuffer(file); @@ -61,7 +61,7 @@ describe("Packer", () => { }); describe("#toBase64String()", () => { - it("should create a standard docx file", async function() { + it("should create a standard docx file", async function () { this.timeout(99999999); const str = await Packer.toBase64String(file); diff --git a/src/file/content-types/content-types.spec.ts b/src/file/content-types/content-types.spec.ts index 1d8e008f92..57d992f83d 100644 --- a/src/file/content-types/content-types.spec.ts +++ b/src/file/content-types/content-types.spec.ts @@ -54,6 +54,14 @@ describe("ContentTypes", () => { }, }); expect(tree["Types"][11]).to.deep.equal({ + Override: { + _attr: { + ContentType: "application/vnd.openxmlformats-officedocument.custom-properties+xml", + PartName: "/docProps/custom.xml", + }, + }, + }); + expect(tree["Types"][12]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml", @@ -61,7 +69,7 @@ describe("ContentTypes", () => { }, }, }); - expect(tree["Types"][12]).to.deep.equal({ + expect(tree["Types"][13]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", @@ -69,7 +77,7 @@ describe("ContentTypes", () => { }, }, }); - expect(tree["Types"][13]).to.deep.equal({ + expect(tree["Types"][14]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", @@ -77,7 +85,7 @@ describe("ContentTypes", () => { }, }, }); - expect(tree["Types"][14]).to.deep.equal({ + expect(tree["Types"][15]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", @@ -94,7 +102,7 @@ describe("ContentTypes", () => { contentTypes.addFooter(102); const tree = new Formatter().format(contentTypes); - expect(tree["Types"][15]).to.deep.equal({ + expect(tree["Types"][16]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", @@ -103,7 +111,7 @@ describe("ContentTypes", () => { }, }); - expect(tree["Types"][16]).to.deep.equal({ + expect(tree["Types"][17]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", @@ -120,7 +128,7 @@ describe("ContentTypes", () => { contentTypes.addHeader(202); const tree = new Formatter().format(contentTypes); - expect(tree["Types"][15]).to.deep.equal({ + expect(tree["Types"][16]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", @@ -129,7 +137,7 @@ describe("ContentTypes", () => { }, }); - expect(tree["Types"][16]).to.deep.equal({ + expect(tree["Types"][17]).to.deep.equal({ Override: { _attr: { ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", diff --git a/src/file/content-types/content-types.ts b/src/file/content-types/content-types.ts index 86307724fc..34e495d3c0 100644 --- a/src/file/content-types/content-types.ts +++ b/src/file/content-types/content-types.ts @@ -27,6 +27,7 @@ export class ContentTypes extends XmlComponent { this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "/word/styles.xml")); this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml")); + this.root.push(new Override("application/vnd.openxmlformats-officedocument.custom-properties+xml", "/docProps/custom.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml")); diff --git a/src/file/core-properties/properties.ts b/src/file/core-properties/properties.ts index a99c74d98f..17a4baed2a 100644 --- a/src/file/core-properties/properties.ts +++ b/src/file/core-properties/properties.ts @@ -1,6 +1,10 @@ import { XmlComponent } from "file/xml-components"; +import { ICustomPropertyOptions } from "../custom-properties"; +import { IDocumentBackgroundOptions } from "../document"; import { DocumentAttributes } from "../document/document-attributes"; +import { INumberingOptions } from "../numbering"; +import { Paragraph } from "../paragraph"; import { IStylesOptions } from "../styles"; import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components"; @@ -14,6 +18,14 @@ export interface IPropertiesOptions { readonly revision?: string; readonly externalStyles?: string; readonly styles?: IStylesOptions; + readonly numbering?: INumberingOptions; + readonly footnotes?: Paragraph[]; + readonly background?: IDocumentBackgroundOptions; + readonly features?: { + readonly trackRevisions?: boolean; + }; + readonly compatabilityModeVersion?: number; + readonly customProperties?: ICustomPropertyOptions[]; } export class CoreProperties extends XmlComponent { diff --git a/src/file/custom-properties/custom-properties-attributes.ts b/src/file/custom-properties/custom-properties-attributes.ts new file mode 100644 index 0000000000..087c9e98a1 --- /dev/null +++ b/src/file/custom-properties/custom-properties-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface ICustomPropertiesAttributes { + readonly xmlns: string; + readonly vt: string; +} + +export class CustomPropertiesAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { + xmlns: "xmlns", + vt: "xmlns:vt", + }; +} diff --git a/src/file/custom-properties/custom-properties.spec.ts b/src/file/custom-properties/custom-properties.spec.ts new file mode 100644 index 0000000000..a8bc92b7e4 --- /dev/null +++ b/src/file/custom-properties/custom-properties.spec.ts @@ -0,0 +1,66 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { CustomProperties } from "./custom-properties"; + +describe("CustomProperties", () => { + describe("#constructor()", () => { + it("sets the appropriate attributes on the top-level", () => { + const properties = new CustomProperties([]); + const tree = new Formatter().format(properties); + expect(tree).to.deep.equal({ + Properties: { + _attr: { + xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", + "xmlns:vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + }, + }, + }); + }); + + it("should create custom properties with all the attributes given", () => { + const properties = new CustomProperties([ + { name: "Address", value: "123" }, + { name: "Author", value: "456" }, + ]); + const tree = new Formatter().format(properties); + expect(tree).to.deep.equal({ + Properties: [ + { + _attr: { + xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", + "xmlns:vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + }, + }, + { + property: [ + { + _attr: { + fmtid: "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", + pid: "2", + name: "Address", + }, + }, + { + "vt:lpwstr": ["123"], + }, + ], + }, + { + property: [ + { + _attr: { + fmtid: "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", + pid: "3", + name: "Author", + }, + }, + { + "vt:lpwstr": ["456"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/custom-properties/custom-properties.ts b/src/file/custom-properties/custom-properties.ts new file mode 100644 index 0000000000..c254ceeca8 --- /dev/null +++ b/src/file/custom-properties/custom-properties.ts @@ -0,0 +1,37 @@ +import { IXmlableObject, XmlComponent } from "file/xml-components"; +import { CustomPropertiesAttributes } from "./custom-properties-attributes"; +import { CustomProperty, ICustomPropertyOptions } from "./custom-property"; + +export class CustomProperties extends XmlComponent { + // tslint:disable-next-line:readonly-keyword + private nextId: number; + private readonly properties: CustomProperty[] = []; + + constructor(properties: ICustomPropertyOptions[]) { + super("Properties"); + + this.root.push( + new CustomPropertiesAttributes({ + xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", + vt: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + }), + ); + + // I'm not sure why, but every example I have seen starts with 2 + // https://docs.microsoft.com/en-us/office/open-xml/how-to-set-a-custom-property-in-a-word-processing-document + this.nextId = 2; + + for (const property of properties) { + this.addCustomProperty(property); + } + } + + public prepForXml(): IXmlableObject | undefined { + this.properties.forEach((x) => this.root.push(x)); + return super.prepForXml(); + } + + public addCustomProperty(property: ICustomPropertyOptions): void { + this.properties.push(new CustomProperty(this.nextId++, property)); + } +} diff --git a/src/file/custom-properties/custom-property-attributes.ts b/src/file/custom-properties/custom-property-attributes.ts new file mode 100644 index 0000000000..9b2697fe94 --- /dev/null +++ b/src/file/custom-properties/custom-property-attributes.ts @@ -0,0 +1,15 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface ICustomPropertyAttributes { + readonly fmtid: string; + readonly pid: string; + readonly name: string; +} + +export class CustomPropertyAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { + fmtid: "fmtid", + pid: "pid", + name: "name", + }; +} diff --git a/src/file/custom-properties/custom-property.ts b/src/file/custom-properties/custom-property.ts new file mode 100644 index 0000000000..fc18db2667 --- /dev/null +++ b/src/file/custom-properties/custom-property.ts @@ -0,0 +1,28 @@ +import { XmlComponent } from "file/xml-components"; +import { CustomPropertyAttributes } from "./custom-property-attributes"; + +export interface ICustomPropertyOptions { + readonly name: string; + readonly value: string; +} + +export class CustomProperty extends XmlComponent { + constructor(id: number, properties: ICustomPropertyOptions) { + super("property"); + this.root.push( + new CustomPropertyAttributes({ + fmtid: "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", + pid: id.toString(), + name: properties.name, + }), + ); + this.root.push(new CustomPropertyValue(properties.value)); + } +} + +export class CustomPropertyValue extends XmlComponent { + constructor(value: string) { + super("vt:lpwstr"); + this.root.push(value); + } +} diff --git a/src/file/custom-properties/index.ts b/src/file/custom-properties/index.ts new file mode 100644 index 0000000000..132da63d92 --- /dev/null +++ b/src/file/custom-properties/index.ts @@ -0,0 +1,2 @@ +export * from "./custom-properties"; +export * from "./custom-property"; diff --git a/src/file/document-wrapper.spec.ts b/src/file/document-wrapper.spec.ts new file mode 100644 index 0000000000..344fded379 --- /dev/null +++ b/src/file/document-wrapper.spec.ts @@ -0,0 +1,16 @@ +import { expect } from "chai"; + +import { DocumentWrapper } from "./document-wrapper"; + +describe("DocumentWrapper", () => { + describe("#constructor", () => { + it("should create", () => { + const file = new DocumentWrapper({ background: {} }); + + // tslint:disable-next-line: no-unused-expression + expect(file.View).to.be.ok; + // tslint:disable-next-line: no-unused-expression + expect(file.Relationships).to.be.ok; + }); + }); +}); diff --git a/src/file/document-wrapper.ts b/src/file/document-wrapper.ts new file mode 100644 index 0000000000..a699136727 --- /dev/null +++ b/src/file/document-wrapper.ts @@ -0,0 +1,28 @@ +import { Document, IDocumentOptions } from "./document"; +import { Footer } from "./footer"; +import { FootNotes } from "./footnotes"; +import { Header } from "./header/header"; +import { Relationships } from "./relationships"; + +export interface IViewWrapper { + readonly View: Document | Footer | Header | FootNotes; + readonly Relationships: Relationships; +} + +export class DocumentWrapper implements IViewWrapper { + private readonly document: Document; + private readonly relationships: Relationships; + + constructor(options: IDocumentOptions) { + this.document = new Document(options); + this.relationships = new Relationships(); + } + + public get View(): Document { + return this.document; + } + + public get Relationships(): Relationships { + return this.relationships; + } +} diff --git a/src/file/document/body/body.spec.ts b/src/file/document/body/body.spec.ts index a5bc222fb4..3e2a3155eb 100644 --- a/src/file/document/body/body.spec.ts +++ b/src/file/document/body/body.spec.ts @@ -22,9 +22,6 @@ describe("Body", () => { expect(tree).to.deep.equal({ "w:body": [ - { - "w:p": {}, - }, { "w:sectPr": [ { "w:pgSz": { _attr: { "w:w": 10000, "w:h": 10000, "w:orient": "portrait" } } }, @@ -42,7 +39,7 @@ describe("Body", () => { }, }, }, - { "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }, + { "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } }, { "w:docGrid": { _attr: { "w:linePitch": 360 } } }, ], }, diff --git a/src/file/document/body/body.ts b/src/file/document/body/body.ts index e91b72d59a..4b0e588809 100644 --- a/src/file/document/body/body.ts +++ b/src/file/document/body/body.ts @@ -1,4 +1,6 @@ +import { IViewWrapper } from "file/document-wrapper"; import { IXmlableObject, XmlComponent } from "file/xml-components"; + import { Paragraph, ParagraphProperties, TableOfContents } from "../.."; import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties"; @@ -24,12 +26,13 @@ export class Body extends XmlComponent { this.sections.push(new SectionProperties(options)); } - public prepForXml(): IXmlableObject | undefined { + public prepForXml(file?: IViewWrapper): IXmlableObject | undefined { if (this.sections.length === 1) { + this.root.splice(0, 1); this.root.push(this.sections.pop() as SectionProperties); } - return super.prepForXml(); + return super.prepForXml(file); } public push(component: XmlComponent): void { @@ -43,7 +46,7 @@ export class Body extends XmlComponent { private createSectionParagraph(section: SectionProperties): Paragraph { const paragraph = new Paragraph({}); const properties = new ParagraphProperties({}); - properties.addChildElement(section); + properties.push(section); paragraph.addChildElement(properties); return paragraph; } diff --git a/src/file/document/body/section-properties/columns/columns-attributes.ts b/src/file/document/body/section-properties/columns/columns-attributes.ts index b5a14315cc..40140bd63f 100644 --- a/src/file/document/body/section-properties/columns/columns-attributes.ts +++ b/src/file/document/body/section-properties/columns/columns-attributes.ts @@ -1,13 +1,13 @@ import { XmlAttributeComponent } from "file/xml-components"; -export interface IColumnsAttributes { +export class ColumnsAttributes extends XmlAttributeComponent<{ readonly space?: number; readonly num?: number; -} - -export class ColumnsAttributes extends XmlAttributeComponent { + readonly separate?: boolean; +}> { protected readonly xmlKeys = { space: "w:space", num: "w:num", + separate: "w:sep", }; } diff --git a/src/file/document/body/section-properties/columns/columns.ts b/src/file/document/body/section-properties/columns/columns.ts index d8c7eef577..c074f189d9 100644 --- a/src/file/document/body/section-properties/columns/columns.ts +++ b/src/file/document/body/section-properties/columns/columns.ts @@ -2,12 +2,13 @@ import { XmlComponent } from "file/xml-components"; import { ColumnsAttributes } from "./columns-attributes"; export class Columns extends XmlComponent { - constructor(space: number, num: number) { + constructor(space: number, num: number, separate: boolean) { super("w:cols"); this.root.push( new ColumnsAttributes({ space: space, num: num, + separate: separate, }), ); } diff --git a/src/file/document/body/section-properties/index.ts b/src/file/document/body/section-properties/index.ts index a8985b1249..ee0820c640 100644 --- a/src/file/document/body/section-properties/index.ts +++ b/src/file/document/body/section-properties/index.ts @@ -5,3 +5,5 @@ export * from "./page-size"; export * from "./page-number"; export * from "./page-border"; export * from "./line-number"; +export * from "./vertical-align"; +export * from "./type"; diff --git a/src/file/document/body/section-properties/page-number/page-number.ts b/src/file/document/body/section-properties/page-number/page-number.ts index d876c265af..b6bd5a6e86 100644 --- a/src/file/document/body/section-properties/page-number/page-number.ts +++ b/src/file/document/body/section-properties/page-number/page-number.ts @@ -14,6 +14,7 @@ export enum PageNumberFormat { ORDINAL_TEXT = "ordinalText", UPPER_LETTER = "upperLetter", UPPER_ROMAN = "upperRoman", + DECIMAL_FULL_WIDTH = "decimalFullWidth", } export interface IPageNumberTypeAttributes { diff --git a/src/file/document/body/section-properties/section-properties.spec.ts b/src/file/document/body/section-properties/section-properties.spec.ts index abdbf9e1ed..dea16f5ac3 100644 --- a/src/file/document/body/section-properties/section-properties.spec.ts +++ b/src/file/document/body/section-properties/section-properties.spec.ts @@ -1,5 +1,6 @@ import { expect } from "chai"; +import { convertInchesToTwip } from "convenience-functions"; import { Formatter } from "export/formatter"; import { FooterWrapper } from "file/footer-wrapper"; import { HeaderWrapper } from "file/header-wrapper"; @@ -8,6 +9,8 @@ import { Media } from "file/media"; import { PageBorderOffsetFrom } from "./page-border"; import { PageNumberFormat } from "./page-number"; import { SectionProperties } from "./section-properties"; +import { SectionType } from "./type/section-type-attributes"; +import { SectionVerticalAlignValue } from "./vertical-align"; describe("SectionProperties", () => { describe("#constructor()", () => { @@ -17,10 +20,10 @@ describe("SectionProperties", () => { const properties = new SectionProperties({ width: 11906, height: 16838, - top: 1440, - right: 1440, - bottom: 1440, - left: 1440, + top: convertInchesToTwip(1), + right: convertInchesToTwip(1), + bottom: convertInchesToTwip(1), + left: convertInchesToTwip(1), header: 708, footer: 708, gutter: 0, @@ -28,8 +31,9 @@ describe("SectionProperties", () => { column: { space: 708, count: 1, + separate: true, }, - linePitch: 360, + linePitch: convertInchesToTwip(0.25), headers: { default: new HeaderWrapper(media, 100), }, @@ -39,6 +43,7 @@ describe("SectionProperties", () => { pageNumberStart: 10, pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT, titlePage: true, + verticalAlign: SectionVerticalAlignValue.TOP, }); const tree = new Formatter().format(properties); expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]); @@ -59,7 +64,7 @@ describe("SectionProperties", () => { }, }); - expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }); + expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": true, "w:num": 1 } } }); expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } }); expect(tree["w:sectPr"][4]).to.deep.equal({ "w:headerReference": { _attr: { "r:id": "rId100", "w:type": "default" } } }); expect(tree["w:sectPr"][5]).to.deep.equal({ "w:footerReference": { _attr: { "r:id": "rId200", "w:type": "even" } } }); @@ -86,7 +91,7 @@ describe("SectionProperties", () => { }, }, }); - expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }); + expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } }); expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } }); }); @@ -196,5 +201,17 @@ describe("SectionProperties", () => { const pgNumType = tree["w:sectPr"].find((item) => item["w:pgNumType"] !== undefined); expect(pgNumType).to.equal(undefined); }); + + it("should create section properties with section type", () => { + const properties = new SectionProperties({ + type: SectionType.CONTINUOUS, + }); + const tree = new Formatter().format(properties); + expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]); + const type = tree["w:sectPr"].find((item) => item["w:type"] !== undefined); + expect(type).to.deep.equal({ + "w:type": { _attr: { "w:val": "continuous" } }, + }); + }); }); }); diff --git a/src/file/document/body/section-properties/section-properties.ts b/src/file/document/body/section-properties/section-properties.ts index 072f68acca..83bb93e580 100644 --- a/src/file/document/body/section-properties/section-properties.ts +++ b/src/file/document/body/section-properties/section-properties.ts @@ -1,4 +1,5 @@ // http://officeopenxml.com/WPsection.php +import { convertInchesToTwip } from "convenience-functions"; import { FooterWrapper } from "file/footer-wrapper"; import { HeaderWrapper } from "file/header-wrapper"; import { XmlComponent } from "file/xml-components"; @@ -18,6 +19,9 @@ import { IPageNumberTypeAttributes, PageNumberType } from "./page-number"; import { PageSize } from "./page-size/page-size"; import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes"; import { TitlePage } from "./title-page/title-page"; +import { Type } from "./type/section-type"; +import { SectionType } from "./type/section-type-attributes"; +import { ISectionVerticalAlignAttributes, SectionVerticalAlign } from "./vertical-align"; export interface IHeaderFooterGroup { readonly default?: T; @@ -45,16 +49,21 @@ export type SectionPropertiesOptions = IPageSizeAttributes & IPageNumberTypeAttributes & ILineNumberAttributes & IPageBordersOptions & - ITitlePageOptions & { + ITitlePageOptions & + ISectionVerticalAlignAttributes & { readonly column?: { readonly space?: number; readonly count?: number; + readonly separate?: boolean; }; + readonly type?: SectionType; }; // Need to decouple this from the attributes export class SectionProperties extends XmlComponent { - private readonly options: SectionPropertiesOptions; + public readonly width: number; + public readonly rightMargin: number; + public readonly leftMargin: number; constructor(options: SectionPropertiesOptions = { column: {} }) { super("w:sectPr"); @@ -62,10 +71,10 @@ export class SectionProperties extends XmlComponent { const { width = 11906, height = 16838, - top = 1440, - right = 1440, - bottom = 1440, - left = 1440, + top = convertInchesToTwip(1), + right = convertInchesToTwip(1), + bottom = convertInchesToTwip(1), + left = convertInchesToTwip(1), header = 708, footer = 708, gutter = 0, @@ -87,12 +96,17 @@ export class SectionProperties extends XmlComponent { pageBorderBottom, pageBorderLeft, titlePage = false, + verticalAlign, + type, } = options; - this.options = options; + this.leftMargin = left; + this.rightMargin = right; + this.width = width; + this.root.push(new PageSize(width, height, orientation)); this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter, mirror)); - this.root.push(new Columns(column.space ? column.space : 708, column.count ? column.count : 1)); + this.root.push(new Columns(column.space ? column.space : 708, column.count ? column.count : 1, column.separate ?? false)); this.root.push(new DocumentGrid(linePitch)); this.addHeaders(headers); @@ -121,6 +135,14 @@ export class SectionProperties extends XmlComponent { if (titlePage) { this.root.push(new TitlePage()); } + + if (verticalAlign) { + this.root.push(new SectionVerticalAlign(verticalAlign)); + } + + if (type) { + this.root.push(new Type(type)); + } } private addHeaders(headers?: IHeaderFooterGroup): void { @@ -129,7 +151,7 @@ export class SectionProperties extends XmlComponent { this.root.push( new HeaderReference({ headerType: HeaderReferenceType.DEFAULT, - headerId: headers.default.Header.ReferenceId, + headerId: headers.default.View.ReferenceId, }), ); } @@ -138,7 +160,7 @@ export class SectionProperties extends XmlComponent { this.root.push( new HeaderReference({ headerType: HeaderReferenceType.FIRST, - headerId: headers.first.Header.ReferenceId, + headerId: headers.first.View.ReferenceId, }), ); } @@ -147,7 +169,7 @@ export class SectionProperties extends XmlComponent { this.root.push( new HeaderReference({ headerType: HeaderReferenceType.EVEN, - headerId: headers.even.Header.ReferenceId, + headerId: headers.even.View.ReferenceId, }), ); } @@ -160,7 +182,7 @@ export class SectionProperties extends XmlComponent { this.root.push( new FooterReference({ footerType: FooterReferenceType.DEFAULT, - footerId: footers.default.Footer.ReferenceId, + footerId: footers.default.View.ReferenceId, }), ); } @@ -169,7 +191,7 @@ export class SectionProperties extends XmlComponent { this.root.push( new FooterReference({ footerType: FooterReferenceType.FIRST, - footerId: footers.first.Footer.ReferenceId, + footerId: footers.first.View.ReferenceId, }), ); } @@ -178,14 +200,10 @@ export class SectionProperties extends XmlComponent { this.root.push( new FooterReference({ footerType: FooterReferenceType.EVEN, - footerId: footers.even.Footer.ReferenceId, + footerId: footers.even.View.ReferenceId, }), ); } } } - - public get Options(): SectionPropertiesOptions { - return this.options; - } } diff --git a/src/file/document/body/section-properties/type/index.ts b/src/file/document/body/section-properties/type/index.ts new file mode 100644 index 0000000000..fd7a8abd9c --- /dev/null +++ b/src/file/document/body/section-properties/type/index.ts @@ -0,0 +1,2 @@ +export * from "./section-type"; +export * from "./section-type-attributes"; diff --git a/src/file/document/body/section-properties/type/section-type-attributes.ts b/src/file/document/body/section-properties/type/section-type-attributes.ts new file mode 100644 index 0000000000..4ac8dd60b4 --- /dev/null +++ b/src/file/document/body/section-properties/type/section-type-attributes.ts @@ -0,0 +1,17 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export enum SectionType { + CONTINUOUS = "continuous", + EVEN_PAGE = "evenPage", + NEXT_COLUMN = "nextColumn", + NEXT_PAGE = "nextPage", + ODD_PAGE = "oddPage", +} + +export class SectionTypeAttributes extends XmlAttributeComponent<{ + readonly val: SectionType; +}> { + protected readonly xmlKeys = { + val: "w:val", + }; +} diff --git a/src/file/document/body/section-properties/type/section-type.spec.ts b/src/file/document/body/section-properties/type/section-type.spec.ts new file mode 100644 index 0000000000..7276825fab --- /dev/null +++ b/src/file/document/body/section-properties/type/section-type.spec.ts @@ -0,0 +1,35 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { Type } from "./section-type"; +import { SectionType } from "./section-type-attributes"; + +describe("Type", () => { + it("should create with even page section type", () => { + const sectionType = new Type(SectionType.EVEN_PAGE); + + const tree = new Formatter().format(sectionType); + + expect(tree).to.deep.equal({ + "w:type": { + _attr: { + "w:val": "evenPage", + }, + }, + }); + }); + + it("should create with continuous section type", () => { + const sectionType = new Type(SectionType.CONTINUOUS); + + const tree = new Formatter().format(sectionType); + + expect(tree).to.deep.equal({ + "w:type": { + _attr: { + "w:val": "continuous", + }, + }, + }); + }); +}); diff --git a/src/file/document/body/section-properties/type/section-type.ts b/src/file/document/body/section-properties/type/section-type.ts new file mode 100644 index 0000000000..3a11f2e041 --- /dev/null +++ b/src/file/document/body/section-properties/type/section-type.ts @@ -0,0 +1,10 @@ +// http://officeopenxml.com/WPsection.php +import { XmlComponent } from "file/xml-components"; +import { SectionType, SectionTypeAttributes } from "./section-type-attributes"; + +export class Type extends XmlComponent { + constructor(value: SectionType) { + super("w:type"); + this.root.push(new SectionTypeAttributes({ val: value })); + } +} diff --git a/src/file/document/body/section-properties/vertical-align/index.ts b/src/file/document/body/section-properties/vertical-align/index.ts new file mode 100644 index 0000000000..1f3fb76bb2 --- /dev/null +++ b/src/file/document/body/section-properties/vertical-align/index.ts @@ -0,0 +1,2 @@ +export * from "./vertical-align"; +export * from "./vertical-align-attributes"; diff --git a/src/file/document/body/section-properties/vertical-align/vertical-align-attributes.ts b/src/file/document/body/section-properties/vertical-align/vertical-align-attributes.ts new file mode 100644 index 0000000000..fa09712a00 --- /dev/null +++ b/src/file/document/body/section-properties/vertical-align/vertical-align-attributes.ts @@ -0,0 +1,12 @@ +import { XmlAttributeComponent } from "file/xml-components"; +import { SectionVerticalAlignValue } from "./vertical-align"; + +export interface ISectionVerticalAlignAttributes { + readonly verticalAlign?: SectionVerticalAlignValue; +} + +export class SectionVerticalAlignAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { + verticalAlign: "w:val", + }; +} diff --git a/src/file/document/body/section-properties/vertical-align/vertical-align.ts b/src/file/document/body/section-properties/vertical-align/vertical-align.ts new file mode 100644 index 0000000000..b025059d16 --- /dev/null +++ b/src/file/document/body/section-properties/vertical-align/vertical-align.ts @@ -0,0 +1,18 @@ +// http://officeopenxml.com/WPsection.php + +import { XmlComponent } from "file/xml-components"; +import { SectionVerticalAlignAttributes } from "./vertical-align-attributes"; + +export enum SectionVerticalAlignValue { + BOTH = "both", + BOTTOM = "bottom", + CENTER = "center", + TOP = "top", +} + +export class SectionVerticalAlign extends XmlComponent { + constructor(value: SectionVerticalAlignValue) { + super("w:vAlign"); + this.root.push(new SectionVerticalAlignAttributes({ verticalAlign: value })); + } +} diff --git a/src/file/document/document-background/document-background.spec.ts b/src/file/document/document-background/document-background.spec.ts new file mode 100644 index 0000000000..83d1fb36b1 --- /dev/null +++ b/src/file/document/document-background/document-background.spec.ts @@ -0,0 +1,53 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { DocumentBackground } from "./document-background"; + +describe("DocumentBackground", () => { + describe("#constructor()", () => { + it("should create a DocumentBackground with no options and set color to auto", () => { + const documentBackground = new DocumentBackground({}); + const tree = new Formatter().format(documentBackground); + expect(tree).to.deep.equal({ + "w:background": { + _attr: { + "w:color": "FFFFFF", + }, + }, + }); + }); + + it("should create a DocumentBackground with no options and set color to value", () => { + const documentBackground = new DocumentBackground({ color: "ffff00" }); + const tree = new Formatter().format(documentBackground); + expect(tree).to.deep.equal({ + "w:background": { + _attr: { + "w:color": "ffff00", + }, + }, + }); + }); + + it("should create a DocumentBackground with no options and set other values", () => { + const documentBackground = new DocumentBackground({ + color: "ffff00", + themeColor: "test", + themeShade: "test", + themeTint: "test", + }); + const tree = new Formatter().format(documentBackground); + expect(tree).to.deep.equal({ + "w:background": { + _attr: { + "w:color": "ffff00", + "w:themeColor": "test", + "w:themeShade": "test", + "w:themeTint": "test", + }, + }, + }); + }); + }); +}); diff --git a/src/file/document/document-background/document-background.ts b/src/file/document/document-background/document-background.ts new file mode 100644 index 0000000000..44b04aabe6 --- /dev/null +++ b/src/file/document/document-background/document-background.ts @@ -0,0 +1,39 @@ +// http://officeopenxml.com/WPdocument.php +// http://www.datypic.com/sc/ooxml/e-w_background-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +export class DocumentBackgroundAttributes extends XmlAttributeComponent<{ + readonly color: string; + readonly themeColor?: string; + readonly themeShade?: string; + readonly themeTint?: string; +}> { + protected readonly xmlKeys = { + color: "w:color", + themeColor: "w:themeColor", + themeShade: "w:themeShade", + themeTint: "w:themeTint", + }; +} + +export interface IDocumentBackgroundOptions { + readonly color?: string; + readonly themeColor?: string; + readonly themeShade?: string; + readonly themeTint?: string; +} + +export class DocumentBackground extends XmlComponent { + constructor(options: IDocumentBackgroundOptions) { + super("w:background"); + + this.root.push( + new DocumentBackgroundAttributes({ + color: options.color ? options.color : "FFFFFF", + themeColor: options.themeColor, + themeShade: options.themeShade, + themeTint: options.themeTint, + }), + ); + } +} diff --git a/src/file/document/document-background/index.ts b/src/file/document/document-background/index.ts new file mode 100644 index 0000000000..604f3da1f2 --- /dev/null +++ b/src/file/document/document-background/index.ts @@ -0,0 +1 @@ +export * from "./document-background"; diff --git a/src/file/document/document.spec.ts b/src/file/document/document.spec.ts index dba489601e..d903ff78aa 100644 --- a/src/file/document/document.spec.ts +++ b/src/file/document/document.spec.ts @@ -8,7 +8,7 @@ describe("Document", () => { let document: Document; beforeEach(() => { - document = new Document(); + document = new Document({ background: {} }); }); describe("#constructor()", () => { @@ -38,6 +38,13 @@ describe("Document", () => { "mc:Ignorable": "w14 w15 wp14", }, }, + { + "w:background": { + _attr: { + "w:color": "FFFFFF", + }, + }, + }, { "w:body": {} }, ], }); diff --git a/src/file/document/document.ts b/src/file/document/document.ts index d8c0c55131..cc33709076 100644 --- a/src/file/document/document.ts +++ b/src/file/document/document.ts @@ -1,15 +1,20 @@ // http://officeopenxml.com/WPdocument.php import { XmlComponent } from "file/xml-components"; -import { Paragraph } from "../paragraph"; +import { ConcreteHyperlink, Paragraph } from "../paragraph"; import { Table } from "../table"; import { TableOfContents } from "../table-of-contents"; import { Body } from "./body"; import { DocumentAttributes } from "./document-attributes"; +import { DocumentBackground, IDocumentBackgroundOptions } from "./document-background"; + +export interface IDocumentOptions { + readonly background: IDocumentBackgroundOptions; +} export class Document extends XmlComponent { private readonly body: Body; - constructor() { + constructor(options: IDocumentOptions) { super("w:document"); this.root.push( new DocumentAttributes({ @@ -33,10 +38,11 @@ export class Document extends XmlComponent { }), ); this.body = new Body(); + this.root.push(new DocumentBackground(options.background)); this.root.push(this.body); } - public add(item: Paragraph | Table | TableOfContents): Document { + public add(item: Paragraph | Table | TableOfContents | ConcreteHyperlink): Document { this.body.push(item); return this; } diff --git a/src/file/document/index.ts b/src/file/document/index.ts index 3430666623..a93dd86f99 100644 --- a/src/file/document/index.ts +++ b/src/file/document/index.ts @@ -1,3 +1,4 @@ export * from "./document"; export * from "./document-attributes"; export * from "./body"; +export * from "./document-background"; diff --git a/src/file/drawing/anchor/anchor.spec.ts b/src/file/drawing/anchor/anchor.spec.ts index 6b86a31346..10d4b08d13 100644 --- a/src/file/drawing/anchor/anchor.spec.ts +++ b/src/file/drawing/anchor/anchor.spec.ts @@ -218,5 +218,150 @@ describe("Anchor", () => { const textWrap = newJson.root[6]; assert.equal(textWrap.rootKey, "wp:wrapTopAndBottom"); }); + + it("should create a Drawing with a margin", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + margins: { + top: 10, + left: 10, + bottom: 10, + right: 10, + }, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + distT: 10, + distB: 10, + distL: 10, + distR: 10, + }); + }); + + it("should create a Drawing with a default margin", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + margins: {}, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + distT: 0, + distB: 0, + distL: 0, + distR: 0, + }); + }); + + it("should create a Drawing with allowOverlap being false", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + allowOverlap: false, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + allowOverlap: "0", + }); + }); + + it("should create a Drawing with behindDocument being true", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + behindDocument: true, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + behindDoc: "1", + }); + }); + + it("should create a Drawing with locked being true", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + lockAnchor: true, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + locked: "1", + }); + }); + + it("should create a Drawing with locked being false", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + layoutInCell: false, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + layoutInCell: "0", + }); + }); + + it("should create a Drawing with a certain z-index", () => { + anchor = createAnchor({ + floating: { + verticalPosition: { + offset: 0, + }, + horizontalPosition: { + offset: 0, + }, + zIndex: 120, + }, + }); + const newJson = Utility.jsonify(anchor); + const anchorAttributes = newJson.root[0].root; + + assert.include(anchorAttributes, { + relativeHeight: 120, + }); + }); }); }); diff --git a/src/file/drawing/anchor/anchor.ts b/src/file/drawing/anchor/anchor.ts index d52c349ebb..7eb4487a89 100644 --- a/src/file/drawing/anchor/anchor.ts +++ b/src/file/drawing/anchor/anchor.ts @@ -11,42 +11,32 @@ import { Extent } from "./../extent/extent"; import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties"; import { AnchorAttributes } from "./anchor-attributes"; -const defaultOptions: IFloating = { - allowOverlap: true, - behindDocument: false, - lockAnchor: false, - layoutInCell: true, - verticalPosition: {}, - horizontalPosition: {}, -}; - export class Anchor extends XmlComponent { constructor(mediaData: IMediaData, dimensions: IMediaDataDimensions, drawingOptions: IDrawingOptions) { super("wp:anchor"); - const floating = { - margins: { - top: 0, - bottom: 0, - left: 0, - right: 0, - }, - ...defaultOptions, + const floating: IFloating = { + allowOverlap: true, + behindDocument: false, + lockAnchor: false, + layoutInCell: true, + verticalPosition: {}, + horizontalPosition: {}, ...drawingOptions.floating, }; this.root.push( new AnchorAttributes({ - distT: floating.margins.top || 0, - distB: floating.margins.bottom || 0, - distL: floating.margins.left || 0, - distR: floating.margins.right || 0, + distT: floating.margins ? floating.margins.top || 0 : 0, + distB: floating.margins ? floating.margins.bottom || 0 : 0, + distL: floating.margins ? floating.margins.left || 0 : 0, + distR: floating.margins ? floating.margins.right || 0 : 0, simplePos: "0", // note: word doesn't fully support - so we use 0 allowOverlap: floating.allowOverlap === true ? "1" : "0", behindDoc: floating.behindDocument === true ? "1" : "0", locked: floating.lockAnchor === true ? "1" : "0", layoutInCell: floating.layoutInCell === true ? "1" : "0", - relativeHeight: dimensions.emus.y, + relativeHeight: floating.zIndex ? floating.zIndex : dimensions.emus.y, }), ); diff --git a/src/file/drawing/floating/floating-position.ts b/src/file/drawing/floating/floating-position.ts index 9191ef1e1b..6c5ad7f332 100644 --- a/src/file/drawing/floating/floating-position.ts +++ b/src/file/drawing/floating/floating-position.ts @@ -1,4 +1,5 @@ // http://officeopenxml.com/drwPicFloating-position.php +// http://officeopenxml.com/drwPicFloating.php import { ITextWrapping } from "../text-wrap"; export enum HorizontalPositionRelativeFrom { @@ -67,4 +68,5 @@ export interface IFloating { readonly layoutInCell?: boolean; readonly margins?: IMargins; readonly wrap?: ITextWrapping; + readonly zIndex?: number; } diff --git a/src/file/drawing/inline/inline.ts b/src/file/drawing/inline/inline.ts index 7c40e7c3b3..bf83e36764 100644 --- a/src/file/drawing/inline/inline.ts +++ b/src/file/drawing/inline/inline.ts @@ -12,7 +12,7 @@ export class Inline extends XmlComponent { private readonly extent: Extent; private readonly graphic: Graphic; - constructor(readonly mediaData: IMediaData, private readonly dimensions: IMediaDataDimensions) { + constructor(mediaData: IMediaData, private readonly dimensions: IMediaDataDimensions) { super("wp:inline"); this.root.push( diff --git a/src/file/file.spec.ts b/src/file/file.spec.ts index b82748ca54..15b389c96e 100644 --- a/src/file/file.spec.ts +++ b/src/file/file.spec.ts @@ -18,10 +18,10 @@ describe("File", () => { children: [], }); - const tree = new Formatter().format(doc.Document.Body); + const tree = new Formatter().format(doc.Document.View.Body); - expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); - expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default"); }); it("should create with correct headers and footers", () => { @@ -37,10 +37,10 @@ describe("File", () => { children: [], }); - const tree = new Formatter().format(doc.Document.Body); + const tree = new Formatter().format(doc.Document.View.Body); - expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); - expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default"); }); it("should create with first headers and footers", () => { @@ -56,10 +56,10 @@ describe("File", () => { children: [], }); - const tree = new Formatter().format(doc.Document.Body); + const tree = new Formatter().format(doc.Document.View.Body); - expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first"); - expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first"); + expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first"); + expect(tree["w:body"][0]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first"); }); it("should create with correct headers", () => { @@ -79,22 +79,98 @@ describe("File", () => { children: [], }); - const tree = new Formatter().format(doc.Document.Body); + const tree = new Formatter().format(doc.Document.View.Body); - expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); - expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first"); - expect(tree["w:body"][1]["w:sectPr"][6]["w:headerReference"]._attr["w:type"]).to.equal("even"); + expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first"); + expect(tree["w:body"][0]["w:sectPr"][6]["w:headerReference"]._attr["w:type"]).to.equal("even"); - expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("default"); - expect(tree["w:body"][1]["w:sectPr"][8]["w:footerReference"]._attr["w:type"]).to.equal("first"); - expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"]._attr["w:type"]).to.equal("even"); + expect(tree["w:body"][0]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("default"); + expect(tree["w:body"][0]["w:sectPr"][8]["w:footerReference"]._attr["w:type"]).to.equal("first"); + expect(tree["w:body"][0]["w:sectPr"][9]["w:footerReference"]._attr["w:type"]).to.equal("even"); + }); + + it("should add child", () => { + const doc = new File(undefined, undefined, [ + { + children: [new Paragraph("test")], + }, + ]); + + const tree = new Formatter().format(doc.Document.View.Body); + + expect(tree).to.deep.equal({ + "w:body": [ + { + "w:p": [ + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "test", + ], + }, + ], + }, + ], + }, + { + "w:sectPr": [ + { + "w:pgSz": { + _attr: { + "w:h": 16838, + "w:orient": "portrait", + "w:w": 11906, + }, + }, + }, + { + "w:pgMar": { + _attr: { + "w:bottom": 1440, + "w:footer": 708, + "w:gutter": 0, + "w:header": 708, + "w:left": 1440, + "w:mirrorMargins": false, + "w:right": 1440, + "w:top": 1440, + }, + }, + }, + { + "w:cols": { + _attr: { + "w:num": 1, + "w:sep": false, + "w:space": 708, + }, + }, + }, + { + "w:docGrid": { + _attr: { + "w:linePitch": 360, + }, + }, + }, + ], + }, + ], + }); }); }); describe("#addSection", () => { it("should call the underlying document's add a Paragraph", () => { const file = new File(); - const spy = sinon.spy(file.Document, "add"); + const spy = sinon.spy(file.Document.View, "add"); file.addSection({ children: [new Paragraph({})], }); @@ -104,7 +180,7 @@ describe("File", () => { it("should call the underlying document's add when adding a Table", () => { const file = new File(); - const spy = sinon.spy(file.Document, "add"); + const spy = sinon.spy(file.Document.View, "add"); file.addSection({ children: [ new Table({ @@ -126,7 +202,7 @@ describe("File", () => { it("should call the underlying document's add when adding an Image (paragraph)", () => { const file = new File(); - const spy = sinon.spy(file.Document, "add"); + const spy = sinon.spy(file.Document.View, "add"); // tslint:disable-next-line:no-any file.addSection({ children: [new Paragraph("")], @@ -139,7 +215,7 @@ describe("File", () => { describe("#addSection", () => { it("should call the underlying document's add", () => { const file = new File(); - const spy = sinon.spy(file.Document, "add"); + const spy = sinon.spy(file.Document.View, "add"); file.addSection({ children: [new TableOfContents()], }); @@ -148,13 +224,201 @@ describe("File", () => { }); }); - describe("#createFootnote", () => { - it("should call the underlying document's createFootnote", () => { - const wrapper = new File(); - const spy = sinon.spy(wrapper.FootNotes, "createFootNote"); - wrapper.createFootnote(new Paragraph("")); + describe("#addTrackRevisionsFeature", () => { + it("should call the underlying document's add", () => { + const file = new File({ + features: { + trackRevisions: true, + }, + }); - expect(spy.called).to.equal(true); + // tslint:disable-next-line: no-unused-expression no-string-literal + expect(file.Settings["trackRevisions"]).to.exist; + }); + }); + + describe("#createFootnote", () => { + it("should create footnote", () => { + const wrapper = new File({ + footnotes: [new Paragraph("hello")], + }); + + const tree = new Formatter().format(wrapper.FootNotes.View); + + expect(tree).to.deep.equal({ + "w:footnotes": [ + { + _attr: { + "mc:Ignorable": "w14 w15 wp14", + "xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math", + "xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006", + "xmlns:o": "urn:schemas-microsoft-com:office:office", + "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + "xmlns:v": "urn:schemas-microsoft-com:vml", + "xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "xmlns:w10": "urn:schemas-microsoft-com:office:word", + "xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml", + "xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml", + "xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml", + "xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + "xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + "xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", + "xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + "xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", + "xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + }, + }, + { + "w:footnote": [ + { + _attr: { + "w:id": -1, + "w:type": "separator", + }, + }, + { + "w:p": [ + { + "w:pPr": [ + { + "w:spacing": { + _attr: { + "w:after": 0, + "w:line": 240, + "w:lineRule": "auto", + }, + }, + }, + ], + }, + { + "w:r": [ + { + "w:rPr": [ + { + "w:rStyle": { + _attr: { + "w:val": "FootnoteReference", + }, + }, + }, + ], + }, + { + "w:footnoteRef": {}, + }, + ], + }, + { + "w:r": [ + { + "w:separator": {}, + }, + ], + }, + ], + }, + ], + }, + { + "w:footnote": [ + { + _attr: { + "w:id": 0, + "w:type": "continuationSeparator", + }, + }, + { + "w:p": [ + { + "w:pPr": [ + { + "w:spacing": { + _attr: { + "w:after": 0, + "w:line": 240, + "w:lineRule": "auto", + }, + }, + }, + ], + }, + { + "w:r": [ + { + "w:rPr": [ + { + "w:rStyle": { + _attr: { + "w:val": "FootnoteReference", + }, + }, + }, + ], + }, + { + "w:footnoteRef": {}, + }, + ], + }, + { + "w:r": [ + { + "w:continuationSeparator": {}, + }, + ], + }, + ], + }, + ], + }, + { + "w:footnote": [ + { + _attr: { + "w:id": 1, + }, + }, + { + "w:p": [ + { + "w:r": [ + { + "w:rPr": [ + { + "w:rStyle": { + _attr: { + "w:val": "FootnoteReference", + }, + }, + }, + ], + }, + { + "w:footnoteRef": {}, + }, + ], + }, + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "hello", + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); }); }); }); diff --git a/src/file/file.ts b/src/file/file.ts index ccf5fe374c..e91906f3d1 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -1,7 +1,8 @@ import { AppProperties } from "./app-properties/app-properties"; import { ContentTypes } from "./content-types/content-types"; import { CoreProperties, IPropertiesOptions } from "./core-properties"; -import { Document } from "./document"; +import { CustomProperties } from "./custom-properties"; +import { DocumentWrapper } from "./document-wrapper"; import { FooterReferenceType, HeaderReferenceType, @@ -11,14 +12,13 @@ import { import { IPageMarginAttributes } from "./document/body/section-properties/page-margin/page-margin-attributes"; import { IFileProperties } from "./file-properties"; import { FooterWrapper, IDocumentFooter } from "./footer-wrapper"; -import { FootNotes } from "./footnotes"; +import { FootnotesWrapper } from "./footnotes-wrapper"; import { Footer, Header } from "./header"; import { HeaderWrapper, IDocumentHeader } from "./header-wrapper"; import { Media } from "./media"; import { Numbering } from "./numbering"; -import { Bookmark, Hyperlink, Paragraph } from "./paragraph"; +import { Paragraph } from "./paragraph"; import { Relationships } from "./relationships"; -import { TargetModeType } from "./relationships/relationship/relationship"; import { Settings } from "./settings"; import { Styles } from "./styles"; import { ExternalStylesFactory } from "./styles/external-styles-factory"; @@ -40,24 +40,24 @@ export interface ISectionOptions { readonly size?: IPageSizeAttributes; readonly margins?: IPageMarginAttributes; readonly properties?: SectionPropertiesOptions; - readonly children: Array; + readonly children: (Paragraph | Table | TableOfContents)[]; } export class File { // tslint:disable-next-line:readonly-keyword private currentRelationshipId: number = 1; - private readonly document: Document; + private readonly documentWrapper: DocumentWrapper; private readonly headers: IDocumentHeader[] = []; private readonly footers: IDocumentFooter[] = []; - private readonly docRelationships: Relationships; private readonly coreProperties: CoreProperties; private readonly numbering: Numbering; private readonly media: Media; private readonly fileRelationships: Relationships; - private readonly footNotes: FootNotes; + private readonly footnotesWrapper: FootnotesWrapper; private readonly settings: Settings; private readonly contentTypes: ContentTypes; + private readonly customProperties: CustomProperties; private readonly appProperties: AppProperties; private readonly styles: Styles; @@ -71,14 +71,22 @@ export class File { sections: ISectionOptions[] = [], ) { this.coreProperties = new CoreProperties(options); - this.numbering = new Numbering(); - this.docRelationships = new Relationships(); + this.numbering = new Numbering( + options.numbering + ? options.numbering + : { + config: [], + }, + ); this.fileRelationships = new Relationships(); + this.customProperties = new CustomProperties(options.customProperties ?? []); this.appProperties = new AppProperties(); - this.footNotes = new FootNotes(); + this.footnotesWrapper = new FootnotesWrapper(); this.contentTypes = new ContentTypes(); - this.document = new Document(); - this.settings = new Settings(); + this.documentWrapper = new DocumentWrapper({ background: options.background || {} }); + this.settings = new Settings({ + compatabilityModeVersion: options.compatabilityModeVersion, + }); this.media = fileProperties.template && fileProperties.template.media ? fileProperties.template.media : new Media(); @@ -98,7 +106,7 @@ export class File { this.styles = stylesFactory.newInstance(options.externalStyles); } else if (options.styles) { const stylesFactory = new DefaultStylesFactory(); - const defaultStyles = stylesFactory.newInstance(); + const defaultStyles = stylesFactory.newInstance(options.styles.default); this.styles = new Styles({ ...defaultStyles, ...options.styles, @@ -123,36 +131,24 @@ export class File { } for (const section of sections) { - this.document.Body.addSection(section.properties ? section.properties : {}); + this.documentWrapper.View.Body.addSection(section.properties ? section.properties : {}); for (const child of section.children) { - this.document.add(child); + this.documentWrapper.View.add(child); } } - } - public createHyperlink(link: string, text?: string): Hyperlink { - const newText = text === undefined ? link : text; - const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount); - this.docRelationships.createRelationship( - hyperlink.linkId, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", - link, - TargetModeType.EXTERNAL, - ); - return hyperlink; - } + if (options.footnotes) { + for (const paragraph of options.footnotes) { + this.footnotesWrapper.View.createFootNote(paragraph); + } + } - public createInternalHyperLink(anchor: string, text?: string): Hyperlink { - const newText = text === undefined ? anchor : text; - const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount, anchor); - // NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark - // we don't need to create a new relationship. - return hyperlink; - } - - public createBookmark(name: string, text: string = name): Bookmark { - return new Bookmark(name, text, this.docRelationships.RelationshipCount); + if (options.features) { + if (options.features.trackRevisions) { + this.settings.addTrackRevisions(); + } + } } public addSection({ @@ -163,7 +159,7 @@ export class File { properties, children, }: ISectionOptions): void { - this.document.Body.addSection({ + this.documentWrapper.View.Body.addSection({ ...properties, headers: { default: headers.default ? this.createHeader(headers.default) : this.createHeader(new Header()), @@ -180,16 +176,12 @@ export class File { }); for (const child of children) { - this.document.add(child); + this.documentWrapper.View.add(child); } } - public createFootnote(paragraph: Paragraph): void { - this.footNotes.createFootNote(paragraph); - } - public verifyUpdateFields(): void { - if (this.document.getTablesOfContents().length) { + if (this.documentWrapper.View.getTablesOfContents().length) { this.settings.addUpdateFields(); } } @@ -218,8 +210,8 @@ export class File { private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void { this.headers.push({ header, type }); - this.docRelationships.createRelationship( - header.Header.ReferenceId, + this.documentWrapper.Relationships.createRelationship( + header.View.ReferenceId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", `header${this.headers.length}.xml`, ); @@ -228,8 +220,8 @@ export class File { private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT): void { this.footers.push({ footer, type }); - this.docRelationships.createRelationship( - footer.Footer.ReferenceId, + this.documentWrapper.Relationships.createRelationship( + footer.View.ReferenceId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", `footer${this.footers.length}.xml`, ); @@ -252,31 +244,36 @@ export class File { "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties", "docProps/app.xml", ); + this.fileRelationships.createRelationship( + 4, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties", + "docProps/custom.xml", + ); - this.docRelationships.createRelationship( + this.documentWrapper.Relationships.createRelationship( this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml", ); - this.docRelationships.createRelationship( + this.documentWrapper.Relationships.createRelationship( this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml", ); - this.docRelationships.createRelationship( + this.documentWrapper.Relationships.createRelationship( this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", "footnotes.xml", ); - this.docRelationships.createRelationship( + this.documentWrapper.Relationships.createRelationship( this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", "settings.xml", ); } - public get Document(): Document { - return this.document; + public get Document(): DocumentWrapper { + return this.documentWrapper; } public get Styles(): Styles { @@ -295,10 +292,6 @@ export class File { return this.media; } - public get DocumentRelationships(): Relationships { - return this.docRelationships; - } - public get FileRelationships(): Relationships { return this.fileRelationships; } @@ -315,12 +308,16 @@ export class File { return this.contentTypes; } + public get CustomProperties(): CustomProperties { + return this.customProperties; + } + public get AppProperties(): AppProperties { return this.appProperties; } - public get FootNotes(): FootNotes { - return this.footNotes; + public get FootNotes(): FootnotesWrapper { + return this.footnotesWrapper; } public get Settings(): Settings { diff --git a/src/file/footer-wrapper.spec.ts b/src/file/footer-wrapper.spec.ts index 4f3e95acdb..2a32ad7968 100644 --- a/src/file/footer-wrapper.spec.ts +++ b/src/file/footer-wrapper.spec.ts @@ -10,7 +10,7 @@ describe("FooterWrapper", () => { describe("#add", () => { it("should call the underlying footer's addParagraph", () => { const file = new FooterWrapper(new Media(), 1); - const spy = sinon.spy(file.Footer, "add"); + const spy = sinon.spy(file.View, "add"); file.add(new Paragraph({})); expect(spy.called).to.equal(true); @@ -18,7 +18,7 @@ describe("FooterWrapper", () => { it("should call the underlying footer's addParagraph", () => { const file = new FooterWrapper(new Media(), 1); - const spy = sinon.spy(file.Footer, "add"); + const spy = sinon.spy(file.View, "add"); file.add( new Table({ rows: [ @@ -40,7 +40,7 @@ describe("FooterWrapper", () => { describe("#addChildElement", () => { it("should call the underlying footer's addChildElement", () => { const file = new FooterWrapper(new Media(), 1); - const spy = sinon.spy(file.Footer, "addChildElement"); + const spy = sinon.spy(file.View, "addChildElement"); // tslint:disable-next-line:no-any file.addChildElement({} as any); diff --git a/src/file/footer-wrapper.ts b/src/file/footer-wrapper.ts index 8390887ba4..e16a72e974 100644 --- a/src/file/footer-wrapper.ts +++ b/src/file/footer-wrapper.ts @@ -1,6 +1,7 @@ import { XmlComponent } from "file/xml-components"; import { FooterReferenceType } from "./document"; +import { IViewWrapper } from "./document-wrapper"; import { Footer } from "./footer/footer"; import { Media } from "./media"; import { Paragraph } from "./paragraph"; @@ -12,7 +13,7 @@ export interface IDocumentFooter { readonly type: FooterReferenceType; } -export class FooterWrapper { +export class FooterWrapper implements IViewWrapper { private readonly footer: Footer; private readonly relationships: Relationships; @@ -29,7 +30,7 @@ export class FooterWrapper { this.footer.addChildElement(childElement); } - public get Footer(): Footer { + public get View(): Footer { return this.footer; } diff --git a/src/file/footnotes-wrapper.spec.ts b/src/file/footnotes-wrapper.spec.ts new file mode 100644 index 0000000000..6427de6ee6 --- /dev/null +++ b/src/file/footnotes-wrapper.spec.ts @@ -0,0 +1,16 @@ +import { expect } from "chai"; + +import { FootnotesWrapper } from "./footnotes-wrapper"; + +describe("FootnotesWrapper", () => { + describe("#constructor", () => { + it("should create", () => { + const file = new FootnotesWrapper(); + + // tslint:disable-next-line: no-unused-expression + expect(file.View).to.be.ok; + // tslint:disable-next-line: no-unused-expression + expect(file.Relationships).to.be.ok; + }); + }); +}); diff --git a/src/file/footnotes-wrapper.ts b/src/file/footnotes-wrapper.ts new file mode 100644 index 0000000000..c76a8957c2 --- /dev/null +++ b/src/file/footnotes-wrapper.ts @@ -0,0 +1,21 @@ +import { IViewWrapper } from "./document-wrapper"; +import { FootNotes } from "./footnotes/footnotes"; +import { Relationships } from "./relationships"; + +export class FootnotesWrapper implements IViewWrapper { + private readonly footnotess: FootNotes; + private readonly relationships: Relationships; + + constructor() { + this.footnotess = new FootNotes(); + this.relationships = new Relationships(); + } + + public get View(): FootNotes { + return this.footnotess; + } + + public get Relationships(): Relationships { + return this.relationships; + } +} diff --git a/src/file/footnotes/footnote/footnote.spec.ts b/src/file/footnotes/footnote/footnote.spec.ts index 8594cd75fd..49e497d988 100644 --- a/src/file/footnotes/footnote/footnote.spec.ts +++ b/src/file/footnotes/footnote/footnote.spec.ts @@ -7,7 +7,10 @@ import { Footnote, FootnoteType } from "./footnote"; describe("Footnote", () => { describe("#constructor", () => { it("should create a footnote with a footnote type", () => { - const footnote = new Footnote(1, FootnoteType.SEPERATOR); + const footnote = new Footnote({ + id: 1, + type: FootnoteType.SEPERATOR, + }); const tree = new Formatter().format(footnote); expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); @@ -15,7 +18,9 @@ describe("Footnote", () => { }); it("should create a footnote without a footnote type", () => { - const footnote = new Footnote(1); + const footnote = new Footnote({ + id: 1, + }); const tree = new Formatter().format(footnote); expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); diff --git a/src/file/footnotes/footnote/footnote.ts b/src/file/footnotes/footnote/footnote.ts index 60e6e533c8..4ef653ddfb 100644 --- a/src/file/footnotes/footnote/footnote.ts +++ b/src/file/footnotes/footnote/footnote.ts @@ -9,13 +9,18 @@ export enum FootnoteType { CONTINUATION_SEPERATOR = "continuationSeparator", } +export interface IFootnoteOptions { + readonly id: number; + readonly type?: FootnoteType; +} + export class Footnote extends XmlComponent { - constructor(id: number, type?: FootnoteType) { + constructor(options: IFootnoteOptions) { super("w:footnote"); this.root.push( new FootnoteAttributes({ - type: type, - id: id, + type: options.type, + id: options.id, }), ); } diff --git a/src/file/footnotes/footnote/index.ts b/src/file/footnotes/footnote/index.ts new file mode 100644 index 0000000000..11d8ba33a9 --- /dev/null +++ b/src/file/footnotes/footnote/index.ts @@ -0,0 +1 @@ +export * from "./run"; diff --git a/src/file/footnotes/footnote/run/index.ts b/src/file/footnotes/footnote/run/index.ts new file mode 100644 index 0000000000..548e717bbd --- /dev/null +++ b/src/file/footnotes/footnote/run/index.ts @@ -0,0 +1 @@ +export * from "./reference-run"; diff --git a/src/file/footnotes/footnotes.ts b/src/file/footnotes/footnotes.ts index 91ba1d199d..09ed315f4b 100644 --- a/src/file/footnotes/footnotes.ts +++ b/src/file/footnotes/footnotes.ts @@ -36,7 +36,10 @@ export class FootNotes extends XmlComponent { }), ); - const begin = new Footnote(-1, FootnoteType.SEPERATOR); + const begin = new Footnote({ + id: -1, + type: FootnoteType.SEPERATOR, + }); begin.add( new Paragraph({ spacing: { @@ -49,7 +52,10 @@ export class FootNotes extends XmlComponent { ); this.root.push(begin); - const spacing = new Footnote(0, FootnoteType.CONTINUATION_SEPERATOR); + const spacing = new Footnote({ + id: 0, + type: FootnoteType.CONTINUATION_SEPERATOR, + }); spacing.add( new Paragraph({ spacing: { @@ -64,7 +70,7 @@ export class FootNotes extends XmlComponent { } public createFootNote(paragraph: Paragraph): void { - const footnote = new Footnote(this.currentId); + const footnote = new Footnote({ id: this.currentId }); footnote.add(paragraph); this.root.push(footnote); diff --git a/src/file/footnotes/index.ts b/src/file/footnotes/index.ts index 91f3a9948b..1e11cca76a 100644 --- a/src/file/footnotes/index.ts +++ b/src/file/footnotes/index.ts @@ -1 +1,2 @@ export * from "./footnotes"; +export * from "./footnote"; diff --git a/src/file/header-wrapper.spec.ts b/src/file/header-wrapper.spec.ts index 00ee776a95..c6a7272d16 100644 --- a/src/file/header-wrapper.spec.ts +++ b/src/file/header-wrapper.spec.ts @@ -10,7 +10,7 @@ describe("HeaderWrapper", () => { describe("#add", () => { it("should call the underlying header's addChildElement for Paragraph", () => { const wrapper = new HeaderWrapper(new Media(), 1); - const spy = sinon.spy(wrapper.Header, "add"); + const spy = sinon.spy(wrapper.View, "add"); wrapper.add(new Paragraph({})); expect(spy.called).to.equal(true); @@ -18,7 +18,7 @@ describe("HeaderWrapper", () => { it("should call the underlying header's addChildElement for Table", () => { const wrapper = new HeaderWrapper(new Media(), 1); - const spy = sinon.spy(wrapper.Header, "add"); + const spy = sinon.spy(wrapper.View, "add"); wrapper.add( new Table({ rows: [ @@ -40,7 +40,7 @@ describe("HeaderWrapper", () => { describe("#addChildElement", () => { it("should call the underlying header's addChildElement", () => { const file = new HeaderWrapper(new Media(), 1); - const spy = sinon.spy(file.Header, "addChildElement"); + const spy = sinon.spy(file.View, "addChildElement"); // tslint:disable-next-line:no-any file.addChildElement({} as any); diff --git a/src/file/header-wrapper.ts b/src/file/header-wrapper.ts index 407399a8fe..945a9d674a 100644 --- a/src/file/header-wrapper.ts +++ b/src/file/header-wrapper.ts @@ -1,6 +1,7 @@ import { XmlComponent } from "file/xml-components"; import { HeaderReferenceType } from "./document"; +import { IViewWrapper } from "./document-wrapper"; import { Header } from "./header/header"; import { Media } from "./media"; import { Paragraph } from "./paragraph"; @@ -12,7 +13,7 @@ export interface IDocumentHeader { readonly type: HeaderReferenceType; } -export class HeaderWrapper { +export class HeaderWrapper implements IViewWrapper { private readonly header: Header; private readonly relationships: Relationships; @@ -31,7 +32,7 @@ export class HeaderWrapper { this.header.addChildElement(childElement); } - public get Header(): Header { + public get View(): Header { return this.header; } diff --git a/src/file/header.ts b/src/file/header.ts index 05e227d9f8..5f59ae2bec 100644 --- a/src/file/header.ts +++ b/src/file/header.ts @@ -2,7 +2,7 @@ import { Paragraph } from "./paragraph"; import { Table } from "./table"; export interface IHeaderOptions { - readonly children: Array; + readonly children: (Paragraph | Table)[]; } export class Header { diff --git a/src/file/index.ts b/src/file/index.ts index d14d4d9b1a..18f0a595e4 100644 --- a/src/file/index.ts +++ b/src/file/index.ts @@ -12,3 +12,5 @@ export * from "./xml-components"; export * from "./header-wrapper"; export * from "./footer-wrapper"; export * from "./header"; +export * from "./footnotes"; +export * from "./track-revision"; diff --git a/src/file/media/media.ts b/src/file/media/media.ts index 0d062c6d64..65a7f1bf58 100644 --- a/src/file/media/media.ts +++ b/src/file/media/media.ts @@ -1,14 +1,12 @@ import { IDrawingOptions } from "../drawing"; import { File } from "../file"; -import { FooterWrapper } from "../footer-wrapper"; -import { HeaderWrapper } from "../header-wrapper"; import { PictureRun } from "../paragraph"; import { IMediaData } from "./data"; // import { Image } from "./image"; export class Media { public static addImage( - file: File | HeaderWrapper | FooterWrapper, + file: File, buffer: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number, @@ -21,14 +19,7 @@ export class Media { private static generateId(): string { // https://gist.github.com/6174/6062387 - return ( - Math.random() - .toString(36) - .substring(2, 15) + - Math.random() - .toString(36) - .substring(2, 15) - ); + return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); } private readonly map: Map; @@ -89,7 +80,7 @@ export class Media { return imageData; } - public get Array(): IMediaData[] { + public get Array(): readonly IMediaData[] { const array = new Array(); this.map.forEach((data) => { diff --git a/src/file/numbering/abstract-numbering.spec.ts b/src/file/numbering/abstract-numbering.spec.ts new file mode 100644 index 0000000000..df5416f453 --- /dev/null +++ b/src/file/numbering/abstract-numbering.spec.ts @@ -0,0 +1,823 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { EMPTY_OBJECT } from "file/xml-components"; + +import { AlignmentType, EmphasisMarkType, TabStopPosition } from "../paragraph"; +import { UnderlineType } from "../paragraph/run/underline"; +import { ShadingType } from "../table"; +import { AbstractNumbering } from "./abstract-numbering"; +import { LevelFormat, LevelSuffix } from "./level"; + +describe("AbstractNumbering", () => { + it("stores its ID at its .id property", () => { + const abstractNumbering = new AbstractNumbering(5, []); + expect(abstractNumbering.id).to.equal(5); + }); + + describe("#createLevel", () => { + it("creates a level with the given characteristics", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 3, + format: LevelFormat.LOWER_LETTER, + text: "%1)", + alignment: AlignmentType.END, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "end" } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": LevelFormat.LOWER_LETTER } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } }); + }); + + it("uses 'start' as the default alignment", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 3, + format: LevelFormat.LOWER_LETTER, + text: "%1)", + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "start" } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": LevelFormat.LOWER_LETTER } } }); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } }); + }); + + it("has suffix", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 3, + format: LevelFormat.LOWER_LETTER, + text: "%1)", + alignment: AlignmentType.END, + suffix: LevelSuffix.SPACE, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:suff": { _attr: { "w:val": "space" } } }); + }); + + describe("formatting methods: paragraph properties", () => { + it("#indent", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + indent: { left: 720 }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:ind": { _attr: { "w:left": 720 } } }], + }); + }); + + it("#spacing", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + spacing: { before: 50, after: 150 }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:spacing": { _attr: { "w:before": 50, "w:after": 150 } } }], + }); + }); + + it("#center", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + alignment: AlignmentType.CENTER, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:jc": { _attr: { "w:val": "center" } } }], + }); + }); + + it("#left", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + alignment: AlignmentType.LEFT, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:jc": { _attr: { "w:val": "left" } } }], + }); + }); + + it("#right", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + alignment: AlignmentType.RIGHT, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:jc": { _attr: { "w:val": "right" } } }], + }); + }); + + it("#justified", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + alignment: AlignmentType.JUSTIFIED, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:jc": { _attr: { "w:val": "both" } } }], + }); + }); + + it("#thematicBreak", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + thematicBreak: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [ + { + "w:pBdr": [ + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 1, + "w:val": "single", + "w:sz": 6, + }, + }, + }, + ], + }, + ], + }); + }); + + it("#leftTabStop", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + leftTabStop: 1200, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [ + { + "w:tabs": [{ "w:tab": { _attr: { "w:val": "left", "w:pos": 1200 } } }], + }, + ], + }); + }); + + it("#maxRightTabStop", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + rightTabStop: TabStopPosition.MAX, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [ + { + "w:tabs": [{ "w:tab": { _attr: { "w:val": "right", "w:pos": 9026 } } }], + }, + ], + }); + }); + + it("#keepLines", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + keepLines: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }], + }); + }); + + it("#keepNext", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + paragraph: { + keepNext: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }], + }); + }); + }); + + describe("formatting methods: run properties", () => { + const sizeTests = [ + { + size: 24, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: true, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: false, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: 26, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }], + }, + ]; + sizeTests.forEach(({ size, sizeComplexScript, expected }) => { + it(`#size ${size} cs ${sizeComplexScript}`, () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { size, sizeComplexScript }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected }); + }); + }); + + it("#smallCaps", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + smallCaps: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }], + }); + }); + + it("#allCaps", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + allCaps: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }], + }); + }); + + it("#strike", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + strike: true, + }, + }, + }, + ]); + + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }], + }); + }); + + it("#doubleStrike", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + doubleStrike: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }], + }); + }); + + it("#subScript", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + subScript: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "subscript" } } }], + }); + }); + + it("#superScript", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + superScript: true, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "superscript" } } }], + }); + }); + + it("#font by name", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + font: "Times", + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [ + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:cs": "Times", + "w:eastAsia": "Times", + "w:hAnsi": "Times", + }, + }, + }, + ], + }); + }); + + it("#font for ascii and eastAsia", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + font: { + ascii: "Times", + eastAsia: "KaiTi", + }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [ + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:eastAsia": "KaiTi", + }, + }, + }, + ], + }); + }); + + const boldTests = [ + { + bold: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: false, + expected: [{ "w:b": { _attr: { "w:val": true } } }], + }, + ]; + boldTests.forEach(({ bold, boldComplexScript, expected }) => { + it(`#bold ${bold} cs ${boldComplexScript}`, () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { bold, boldComplexScript }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected }); + }); + }); + + const italicsTests = [ + { + italics: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: false, + expected: [{ "w:i": { _attr: { "w:val": true } } }], + }, + ]; + italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { + it(`#italics ${italics} cs ${italicsComplexScript}`, () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { italics, italicsComplexScript }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected }); + }); + }); + + const highlightTests = [ + { + highlight: "005599", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: true, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: false, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: "550099", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }], + }, + ]; + highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => { + it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { highlight, highlightComplexScript }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected }); + }); + }); + + const shadingTests = [ + { + shadow: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: true, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: false, + expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "00FF00", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } }, + ], + }, + ]; + shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => { + it("#shadow correctly", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { shadow, shading, shadingComplexScript }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected }); + }); + }); + + describe("#underline", () => { + it("should set underline to 'single' if no arguments are given", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + underline: {}, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:u": { _attr: { "w:val": "single" } } }], + }); + }); + + it("should set the style if given", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + underline: { + type: UnderlineType.DOUBLE, + }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:u": { _attr: { "w:val": "double" } } }], + }); + }); + + it("should set the style and color if given", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + underline: { + type: UnderlineType.DOUBLE, + color: "005599", + }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:u": { _attr: { "w:val": "double", "w:color": "005599" } } }], + }); + }); + }); + + describe("#emphasisMark", () => { + it("should set emphasisMark to 'dot' if no arguments are given", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + emphasisMark: {}, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }); + }); + + it("should set the style if given", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + emphasisMark: { + type: EmphasisMarkType.DOT, + }, + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }); + }); + }); + + it("#color", () => { + const abstractNumbering = new AbstractNumbering(1, [ + { + level: 0, + format: LevelFormat.LOWER_ROMAN, + text: "%0.", + style: { + run: { + color: "123456", + }, + }, + }, + ]); + const tree = new Formatter().format(abstractNumbering); + expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ + "w:rPr": [{ "w:color": { _attr: { "w:val": "123456" } } }], + }); + }); + }); + }); +}); diff --git a/src/file/numbering/abstract-numbering.ts b/src/file/numbering/abstract-numbering.ts index e42e2e4fc8..2eed73fe39 100644 --- a/src/file/numbering/abstract-numbering.ts +++ b/src/file/numbering/abstract-numbering.ts @@ -1,5 +1,6 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -import { Level } from "./level"; + +import { ILevelsOptions, Level } from "./level"; import { MultiLevelType } from "./multi-level-type"; interface IAbstractNumberingAttributesProperties { @@ -17,7 +18,7 @@ class AbstractNumberingAttributes extends XmlAttributeComponent { + describe("#overrideLevel", () => { + let concreteNumbering: ConcreteNumbering; + beforeEach(() => { + concreteNumbering = new ConcreteNumbering(0, 1); + }); + + it("sets a new override level for the given level number", () => { + concreteNumbering.overrideLevel(3); + const tree = new Formatter().format(concreteNumbering); + expect(tree["w:num"]).to.include({ + "w:lvlOverride": [ + { _attr: { "w:ilvl": 3 } }, + { + "w:lvl": [ + { _attr: { "w:ilvl": 3, "w15:tentative": 1 } }, + { "w:start": { _attr: { "w:val": 1 } } }, + { "w:lvlJc": { _attr: { "w:val": "start" } } }, + ], + }, + ], + }); + }); + + it("sets the startOverride element if start is given", () => { + concreteNumbering.overrideLevel(1, 9); + const tree = new Formatter().format(concreteNumbering); + expect(tree["w:num"]).to.include({ + "w:lvlOverride": [ + { + _attr: { + "w:ilvl": 1, + }, + }, + { + "w:startOverride": { + _attr: { + "w:val": 9, + }, + }, + }, + { + "w:lvl": [ + { _attr: { "w:ilvl": 1, "w15:tentative": 1 } }, + { "w:start": { _attr: { "w:val": 1 } } }, + { "w:lvlJc": { _attr: { "w:val": "start" } } }, + ], + }, + ], + }); + }); + + it("sets the lvl element if overrideLevel.Level is accessed", () => { + const ol = concreteNumbering.overrideLevel(1); + expect(ol.Level).to.be.instanceof(LevelForOverride); + const tree = new Formatter().format(concreteNumbering); + + expect(tree["w:num"]).to.include({ + "w:lvlOverride": [ + { _attr: { "w:ilvl": 1 } }, + { + "w:lvl": [ + { _attr: { "w:ilvl": 1, "w15:tentative": 1 } }, + { "w:start": { _attr: { "w:val": 1 } } }, + { "w:lvlJc": { _attr: { "w:val": "start" } } }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/numbering/level.ts b/src/file/numbering/level.ts index bdc65fbba4..22ff07acf3 100644 --- a/src/file/numbering/level.ts +++ b/src/file/numbering/level.ts @@ -1,21 +1,25 @@ +// http://officeopenxml.com/WPnumbering-numFmt.php import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components"; -import { - Alignment, - AlignmentType, - IIndentAttributesProperties, - Indent, - ISpacingProperties, - KeepLines, - KeepNext, - Spacing, - TabStop, - TabStopType, - ThematicBreak, -} from "../paragraph/formatting"; -import { ParagraphProperties } from "../paragraph/properties"; -import * as formatting from "../paragraph/run/formatting"; -import { RunProperties } from "../paragraph/run/properties"; -import { UnderlineType } from "../paragraph/run/underline"; +import { AlignmentType } from "../paragraph/formatting"; +import { IParagraphStylePropertiesOptions, ParagraphProperties } from "../paragraph/properties"; +import { IRunStylePropertiesOptions, RunProperties } from "../paragraph/run/properties"; + +export enum LevelFormat { + BULLET = "bullet", + CARDINAL_TEXT = "cardinalText", + CHICAGO = "chicago", + DECIMAL = "decimal", + DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle", + DECIMAL_ENCLOSED_FULLSTOP = "decimalEnclosedFullstop", + DECIMAL_ENCLOSED_PARENTHESES = "decimalEnclosedParen", + DECIMAL_ZERO = "decimalZero", + LOWER_LETTER = "lowerLetter", + LOWER_ROMAN = "lowerRoman", + NONE = "none", + ORDINAL_TEXT = "ordinalText", + UPPER_LETTER = "upperLetter", + UPPER_ROMAN = "upperRoman", +} interface ILevelAttributesProperties { readonly ilvl?: number; @@ -63,7 +67,7 @@ class LevelText extends XmlComponent { } class LevelJc extends XmlComponent { - constructor(value: string) { + constructor(value: AlignmentType) { super("w:lvlJc"); this.root.push( new Attributes({ @@ -79,6 +83,19 @@ export enum LevelSuffix { TAB = "tab", } +export interface ILevelsOptions { + readonly level: number; + readonly format?: LevelFormat; + readonly text?: string; + readonly alignment?: AlignmentType; + readonly start?: number; + readonly suffix?: LevelSuffix; + readonly style?: { + readonly run?: IRunStylePropertiesOptions; + readonly paragraph?: IParagraphStylePropertiesOptions; + }; +} + class Suffix extends XmlComponent { constructor(value: LevelSuffix) { super("w:suff"); @@ -94,7 +111,7 @@ export class LevelBase extends XmlComponent { private readonly paragraphProperties: ParagraphProperties; private readonly runProperties: RunProperties; - constructor(level: number, start?: number, numberFormat?: string, levelText?: string, lvlJc?: string) { + constructor({ level, format, text, alignment = AlignmentType.START, start = 1, style, suffix }: ILevelsOptions) { super("w:lvl"); this.root.push( new LevelAttributes({ @@ -103,174 +120,34 @@ export class LevelBase extends XmlComponent { }), ); - if (start !== undefined) { - this.root.push(new Start(start)); - } - if (numberFormat !== undefined) { - this.root.push(new NumberFormat(numberFormat)); - } - if (levelText !== undefined) { - this.root.push(new LevelText(levelText)); - } - if (lvlJc !== undefined) { - this.root.push(new LevelJc(lvlJc)); + this.root.push(new Start(start)); + this.root.push(new LevelJc(alignment)); + + if (format) { + this.root.push(new NumberFormat(format)); } - this.paragraphProperties = new ParagraphProperties({}); - this.runProperties = new RunProperties(); + if (text) { + this.root.push(new LevelText(text)); + } + + this.paragraphProperties = new ParagraphProperties(style && style.paragraph); + this.runProperties = new RunProperties(style && style.run); this.root.push(this.paragraphProperties); this.root.push(this.runProperties); - } - public setSuffix(value: LevelSuffix): LevelBase { - this.root.push(new Suffix(value)); - return this; - } - - public addParagraphProperty(property: XmlComponent): Level { - this.paragraphProperties.push(property); - return this; - } - - public addRunProperty(property: XmlComponent): Level { - this.runProperties.push(property); - return this; - } - - // ---------- Run formatting ---------------------- // - - public size(twips: number): Level { - this.addRunProperty(new formatting.Size(twips)); - return this; - } - - public bold(): Level { - this.addRunProperty(new formatting.Bold()); - return this; - } - - public italics(): Level { - this.addRunProperty(new formatting.Italics()); - return this; - } - - public smallCaps(): Level { - this.addRunProperty(new formatting.SmallCaps()); - return this; - } - - public allCaps(): Level { - this.addRunProperty(new formatting.Caps()); - return this; - } - - public strike(): Level { - this.addRunProperty(new formatting.Strike()); - return this; - } - - public doubleStrike(): Level { - this.addRunProperty(new formatting.DoubleStrike()); - return this; - } - - public subScript(): Level { - this.addRunProperty(new formatting.SubScript()); - return this; - } - - public superScript(): Level { - this.addRunProperty(new formatting.SuperScript()); - return this; - } - - public underline(underlineType?: UnderlineType, color?: string): Level { - this.addRunProperty(new formatting.Underline(underlineType, color)); - return this; - } - - public color(color: string): Level { - this.addRunProperty(new formatting.Color(color)); - return this; - } - - public font(fontName: string): Level { - this.addRunProperty(new formatting.RunFonts(fontName)); - return this; - } - - public highlight(color: string): Level { - this.addRunProperty(new formatting.Highlight(color)); - return this; - } - - public shadow(value: string, fill: string, color: string): Level { - this.addRunProperty(new formatting.Shading(value, fill, color)); - return this; - } - // --------------------- Paragraph formatting ------------------------ // - - public center(): Level { - this.addParagraphProperty(new Alignment(AlignmentType.CENTER)); - return this; - } - - public left(): Level { - this.addParagraphProperty(new Alignment(AlignmentType.LEFT)); - return this; - } - - public right(): Level { - this.addParagraphProperty(new Alignment(AlignmentType.RIGHT)); - return this; - } - - public justified(): Level { - this.addParagraphProperty(new Alignment(AlignmentType.BOTH)); - return this; - } - - public thematicBreak(): Level { - this.addParagraphProperty(new ThematicBreak()); - return this; - } - - public rightTabStop(position: number): Level { - return this.addParagraphProperty(new TabStop(TabStopType.RIGHT, position)); - } - - public leftTabStop(position: number): Level { - this.addParagraphProperty(new TabStop(TabStopType.LEFT, position)); - return this; - } - - public indent(attrs: IIndentAttributesProperties): Level { - this.addParagraphProperty(new Indent(attrs)); - return this; - } - - public spacing(params: ISpacingProperties): Level { - this.addParagraphProperty(new Spacing(params)); - return this; - } - - public keepNext(): Level { - this.addParagraphProperty(new KeepNext()); - return this; - } - - public keepLines(): Level { - this.addParagraphProperty(new KeepLines()); - return this; + if (suffix) { + this.root.push(new Suffix(suffix)); + } } } export class Level extends LevelBase { // This is the level that sits under abstractNum. We make a // handful of properties required - constructor(level: number, numberFormat: string, levelText: string, lvlJc: string) { - super(level, 1, numberFormat, levelText, lvlJc); + constructor(options: ILevelsOptions) { + super(options); } } diff --git a/src/file/numbering/num.ts b/src/file/numbering/num.ts index bf552593aa..e459b03d11 100644 --- a/src/file/numbering/num.ts +++ b/src/file/numbering/num.ts @@ -20,10 +20,10 @@ class NumAttributes extends XmlAttributeComponent { protected readonly xmlKeys = { numId: "w:numId" }; } -export class Num extends XmlComponent { +export class ConcreteNumbering extends XmlComponent { public readonly id: number; - constructor(numId: number, abstractNumId: number) { + constructor(numId: number, abstractNumId: number, public readonly reference?: string) { super("w:num"); this.root.push( new NumAttributes({ @@ -55,7 +55,9 @@ export class LevelOverride extends XmlComponent { this.root.push(new StartOverride(start)); } - this.lvl = new LevelForOverride(this.levelNum); + this.lvl = new LevelForOverride({ + level: this.levelNum, + }); this.root.push(this.lvl); } diff --git a/src/file/numbering/numbering.spec.ts b/src/file/numbering/numbering.spec.ts index d5f2f9e168..79a824b67a 100644 --- a/src/file/numbering/numbering.spec.ts +++ b/src/file/numbering/numbering.spec.ts @@ -2,24 +2,15 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { AbstractNumbering } from "./abstract-numbering"; -import { LevelForOverride } from "./level"; -import { Num } from "./num"; import { Numbering } from "./numbering"; -import { EMPTY_OBJECT } from "file/xml-components"; -import { TabStopPosition } from "../paragraph"; -import { UnderlineType } from "../paragraph/run/underline"; - describe("Numbering", () => { - let numbering: Numbering; - - beforeEach(() => { - numbering = new Numbering(); - }); - describe("#constructor", () => { it("creates a default numbering with one abstract and one concrete instance", () => { + const numbering = new Numbering({ + config: [], + }); + const tree = new Formatter().format(numbering); expect(Object.keys(tree)).to.deep.equal(["w:numbering"]); const abstractNums = tree["w:numbering"].filter((el) => el["w:abstractNum"]); @@ -48,418 +39,4 @@ describe("Numbering", () => { }); }); }); - - describe("#createAbstractNumbering", () => { - it("returns a new AbstractNumbering instance", () => { - const a2 = numbering.createAbstractNumbering(); - expect(a2).to.be.instanceof(AbstractNumbering); - }); - - it("assigns a unique ID to each abstract numbering it creates", () => { - const a2 = numbering.createAbstractNumbering(); - const a3 = numbering.createAbstractNumbering(); - expect(a2.id).not.to.equal(a3.id); - }); - }); - - describe("#createConcreteNumbering", () => { - it("returns a new Num instance with its abstract ID set to the AbstractNumbering's ID", () => { - const a2 = numbering.createAbstractNumbering(); - const n = numbering.createConcreteNumbering(a2); - expect(n).to.be.instanceof(Num); - const tree = new Formatter().format(numbering); - const serializedN = tree["w:numbering"].find((obj) => obj["w:num"] && obj["w:num"][0]._attr["w:numId"] === n.id); - expect(serializedN["w:num"][1]["w:abstractNumId"]._attr["w:val"]).to.equal(a2.id); - }); - - it("assigns a unique ID to each concrete numbering it creates", () => { - const a2 = numbering.createAbstractNumbering(); - const n = numbering.createConcreteNumbering(a2); - const n2 = numbering.createConcreteNumbering(a2); - expect(n.id).not.to.equal(n2.id); - }); - }); -}); - -describe("AbstractNumbering", () => { - it("stores its ID at its .id property", () => { - const abstractNumbering = new AbstractNumbering(5); - expect(abstractNumbering.id).to.equal(5); - }); - - describe("#createLevel", () => { - it("creates a level with the given characteristics", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(3, "lowerLetter", "%1)", "end"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } }); - expect(tree["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } }); - expect(tree["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "end" } } }); - expect(tree["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": "lowerLetter" } } }); - expect(tree["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } }); - }); - - it("uses 'start' as the default alignment", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(3, "lowerLetter", "%1)"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } }); - expect(tree["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } }); - expect(tree["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "start" } } }); - expect(tree["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": "lowerLetter" } } }); - expect(tree["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } }); - }); - - describe("formatting methods: paragraph properties", () => { - it("#indent", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerLetter", "%0.").indent({ left: 720 }); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:ind": { _attr: { "w:left": 720 } } }], - }); - }); - - it("#spacing", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerLetter", "%0.").spacing({ before: 50, after: 150 }); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:spacing": { _attr: { "w:before": 50, "w:after": 150 } } }], - }); - }); - - it("#center", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerLetter", "%0.").center(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:jc": { _attr: { "w:val": "center" } } }], - }); - }); - - it("#left", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.", "left").left(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:jc": { _attr: { "w:val": "left" } } }], - }); - }); - - it("#right", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").right(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:jc": { _attr: { "w:val": "right" } } }], - }); - }); - - it("#justified", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").justified(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:jc": { _attr: { "w:val": "both" } } }], - }); - }); - - it("#thematicBreak", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").thematicBreak(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [ - { - "w:pBdr": [ - { - "w:bottom": { - _attr: { - "w:color": "auto", - "w:space": 1, - "w:val": "single", - "w:sz": 6, - }, - }, - }, - ], - }, - ], - }); - }); - - it("#leftTabStop", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").leftTabStop(1200); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [ - { - "w:tabs": [{ "w:tab": { _attr: { "w:val": "left", "w:pos": 1200 } } }], - }, - ], - }); - }); - - it("#maxRightTabStop", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").rightTabStop(TabStopPosition.MAX); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [ - { - "w:tabs": [{ "w:tab": { _attr: { "w:val": "right", "w:pos": 9026 } } }], - }, - ], - }); - }); - - it("#keepLines", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").keepLines(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }], - }); - }); - - it("#keepNext", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").keepNext(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }], - }); - }); - }); - - describe("formatting methods: run properties", () => { - it("#size", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").size(24); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }], - }); - }); - - it("#smallCaps", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").smallCaps(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }], - }); - }); - - it("#allCaps", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").allCaps(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }], - }); - }); - - it("#strike", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").strike(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }], - }); - }); - - it("#doubleStrike", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").doubleStrike(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }], - }); - }); - - it("#subScript", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").subScript(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "subscript" } } }], - }); - }); - - it("#superScript", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").superScript(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "superscript" } } }], - }); - }); - - it("#font", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").font("Times"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [ - { "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } }, - ], - }); - }); - - it("#bold", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").bold(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:b": { _attr: { "w:val": true } } }], - }); - }); - - it("#italics", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").italics(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:i": { _attr: { "w:val": true } } }], - }); - }); - - it("#highlight", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").highlight("005599"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }], - }); - }); - - it("#shadow", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").shadow("pct10", "00FFFF", "FF0000"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], - }); - }); - - describe("#underline", () => { - it("should set underline to 'single' if no arguments are given", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline(); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:u": { _attr: { "w:val": "single" } } }], - }); - }); - - it("should set the style if given", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline(UnderlineType.DOUBLE); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:u": { _attr: { "w:val": "double" } } }], - }); - }); - - it("should set the style and color if given", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline(UnderlineType.DOUBLE, "005599"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:u": { _attr: { "w:val": "double", "w:color": "005599" } } }], - }); - }); - }); - - it("#color", () => { - const abstractNumbering = new AbstractNumbering(1); - const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").color("123456"); - const tree = new Formatter().format(level); - expect(tree["w:lvl"]).to.include({ - "w:rPr": [{ "w:color": { _attr: { "w:val": "123456" } } }], - }); - }); - }); - }); -}); - -describe("concrete numbering", () => { - describe("#overrideLevel", () => { - let numbering; - let abstractNumbering; - let concreteNumbering; - beforeEach(() => { - numbering = new Numbering(); - abstractNumbering = numbering.createAbstractNumbering(); - concreteNumbering = numbering.createConcreteNumbering(abstractNumbering); - }); - - it("sets a new override level for the given level number", () => { - concreteNumbering.overrideLevel(3); - const tree = new Formatter().format(concreteNumbering); - expect(tree["w:num"]).to.include({ - "w:lvlOverride": [ - { - _attr: { - "w:ilvl": 3, - }, - }, - { - "w:lvl": { - _attr: { - "w:ilvl": 3, - "w15:tentative": 1, - }, - }, - }, - ], - }); - }); - - it("sets the startOverride element if start is given", () => { - concreteNumbering.overrideLevel(1, 9); - const tree = new Formatter().format(concreteNumbering); - expect(tree["w:num"]).to.include({ - "w:lvlOverride": [ - { - _attr: { - "w:ilvl": 1, - }, - }, - { - "w:startOverride": { - _attr: { - "w:val": 9, - }, - }, - }, - { - "w:lvl": { - _attr: { - "w:ilvl": 1, - "w15:tentative": 1, - }, - }, - }, - ], - }); - }); - - it("sets the lvl element if overrideLevel.Level is accessed", () => { - const ol = concreteNumbering.overrideLevel(1); - expect(ol.Level).to.be.instanceof(LevelForOverride); - const tree = new Formatter().format(concreteNumbering); - expect(tree["w:num"]).to.include({ - "w:lvlOverride": [ - { _attr: { "w:ilvl": 1 } }, - { - "w:lvl": { _attr: { "w15:tentative": 1, "w:ilvl": 1 } }, - }, - ], - }); - }); - }); }); diff --git a/src/file/numbering/numbering.ts b/src/file/numbering/numbering.ts index 0080b6b349..901f13f4bb 100644 --- a/src/file/numbering/numbering.ts +++ b/src/file/numbering/numbering.ts @@ -1,17 +1,28 @@ -import { Indent } from "file/paragraph"; +// http://officeopenxml.com/WPnumbering.php +import { convertInchesToTwip } from "convenience-functions"; +import { AlignmentType } from "file/paragraph"; import { IXmlableObject, XmlComponent } from "file/xml-components"; + import { DocumentAttributes } from "../document/document-attributes"; import { AbstractNumbering } from "./abstract-numbering"; -import { Num } from "./num"; +import { ILevelsOptions, LevelFormat } from "./level"; +import { ConcreteNumbering } from "./num"; + +export interface INumberingOptions { + readonly config: { + readonly levels: ILevelsOptions[]; + readonly reference: string; + }[]; +} export class Numbering extends XmlComponent { // tslint:disable-next-line:readonly-keyword private nextId: number; - private readonly abstractNumbering: XmlComponent[] = []; - private readonly concreteNumbering: XmlComponent[] = []; + private readonly abstractNumbering: AbstractNumbering[] = []; + private readonly concreteNumbering: ConcreteNumbering[] = []; - constructor() { + constructor(options: INumberingOptions) { super("w:numbering"); this.root.push( new DocumentAttributes({ @@ -37,39 +48,114 @@ export class Numbering extends XmlComponent { this.nextId = 0; - const abstractNumbering = this.createAbstractNumbering(); - - abstractNumbering.createLevel(0, "bullet", "\u25CF", "left").addParagraphProperty(new Indent({ left: 720, hanging: 360 })); - - abstractNumbering.createLevel(1, "bullet", "\u25CB", "left").addParagraphProperty(new Indent({ left: 1440, hanging: 360 })); - - abstractNumbering.createLevel(2, "bullet", "\u25A0", "left").addParagraphProperty(new Indent({ left: 2160, hanging: 360 })); - - abstractNumbering.createLevel(3, "bullet", "\u25CF", "left").addParagraphProperty(new Indent({ left: 2880, hanging: 360 })); - - abstractNumbering.createLevel(4, "bullet", "\u25CB", "left").addParagraphProperty(new Indent({ left: 3600, hanging: 360 })); - - abstractNumbering.createLevel(5, "bullet", "\u25A0", "left").addParagraphProperty(new Indent({ left: 4320, hanging: 360 })); - - abstractNumbering.createLevel(6, "bullet", "\u25CF", "left").addParagraphProperty(new Indent({ left: 5040, hanging: 360 })); - - abstractNumbering.createLevel(7, "bullet", "\u25CB", "left").addParagraphProperty(new Indent({ left: 5760, hanging: 360 })); - - abstractNumbering.createLevel(8, "bullet", "\u25A0", "left").addParagraphProperty(new Indent({ left: 6480, hanging: 360 })); + const abstractNumbering = this.createAbstractNumbering([ + { + level: 0, + format: LevelFormat.BULLET, + text: "\u25CF", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 1, + format: LevelFormat.BULLET, + text: "\u25CB", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: convertInchesToTwip(1), hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 2, + format: LevelFormat.BULLET, + text: "\u25A0", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 2160, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 3, + format: LevelFormat.BULLET, + text: "\u25CF", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 2880, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 4, + format: LevelFormat.BULLET, + text: "\u25CB", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 3600, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 5, + format: LevelFormat.BULLET, + text: "\u25A0", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 4320, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 6, + format: LevelFormat.BULLET, + text: "\u25CF", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 5040, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 7, + format: LevelFormat.BULLET, + text: "\u25CF", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 5760, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + { + level: 8, + format: LevelFormat.BULLET, + text: "\u25CF", + alignment: AlignmentType.LEFT, + style: { + paragraph: { + indent: { left: 6480, hanging: convertInchesToTwip(0.25) }, + }, + }, + }, + ]); this.createConcreteNumbering(abstractNumbering); - } - public createAbstractNumbering(): AbstractNumbering { - const num = new AbstractNumbering(this.nextId++); - this.abstractNumbering.push(num); - return num; - } - - public createConcreteNumbering(abstractNumbering: AbstractNumbering): Num { - const num = new Num(this.nextId++, abstractNumbering.id); - this.concreteNumbering.push(num); - return num; + for (const con of options.config) { + const currentAbstractNumbering = this.createAbstractNumbering(con.levels); + this.createConcreteNumbering(currentAbstractNumbering, con.reference); + } } public prepForXml(): IXmlableObject | undefined { @@ -77,4 +163,20 @@ export class Numbering extends XmlComponent { this.concreteNumbering.forEach((x) => this.root.push(x)); return super.prepForXml(); } + + private createConcreteNumbering(abstractNumbering: AbstractNumbering, reference?: string): ConcreteNumbering { + const num = new ConcreteNumbering(this.nextId++, abstractNumbering.id, reference); + this.concreteNumbering.push(num); + return num; + } + + private createAbstractNumbering(options: ILevelsOptions[]): AbstractNumbering { + const num = new AbstractNumbering(this.nextId++, options); + this.abstractNumbering.push(num); + return num; + } + + public get ConcreteNumbering(): ConcreteNumbering[] { + return this.concreteNumbering; + } } diff --git a/src/file/paragraph/formatting/alignment.ts b/src/file/paragraph/formatting/alignment.ts index 8acf41ee4b..117b584a01 100644 --- a/src/file/paragraph/formatting/alignment.ts +++ b/src/file/paragraph/formatting/alignment.ts @@ -1,4 +1,5 @@ // http://officeopenxml.com/WPalignment.php +// http://officeopenxml.com/WPtableAlignment.php import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; export enum AlignmentType { diff --git a/src/file/paragraph/formatting/bidirectional.spec.ts b/src/file/paragraph/formatting/bidirectional.spec.ts new file mode 100644 index 0000000000..a197ada54e --- /dev/null +++ b/src/file/paragraph/formatting/bidirectional.spec.ts @@ -0,0 +1,15 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { Bidirectional } from "./bidirectional"; + +describe("Bidirectional", () => { + it("should create", () => { + const bidirectional = new Bidirectional(); + const tree = new Formatter().format(bidirectional); + expect(tree).to.deep.equal({ + "w:bidi": {}, + }); + }); +}); diff --git a/src/file/paragraph/formatting/indent.ts b/src/file/paragraph/formatting/indent.ts index 035571b690..3aad7d4e8a 100644 --- a/src/file/paragraph/formatting/indent.ts +++ b/src/file/paragraph/formatting/indent.ts @@ -7,6 +7,7 @@ export interface IIndentAttributesProperties { readonly firstLine?: number; readonly start?: number; readonly end?: number; + readonly right?: number; } class IndentAttributes extends XmlAttributeComponent { @@ -16,6 +17,7 @@ class IndentAttributes extends XmlAttributeComponent { let bookmark: Bookmark; beforeEach(() => { - bookmark = new Bookmark("anchor", "Internal Link", 0); + bookmark = new Bookmark("anchor", "Internal Link"); }); it("should create a bookmark with three root elements", () => { @@ -21,11 +21,8 @@ describe("Bookmark", () => { it("should create a bookmark with the correct attributes on the bookmark start element", () => { const newJson = Utility.jsonify(bookmark); - const attributes = { - name: "anchor", - id: "1", - }; - assert.equal(JSON.stringify(newJson.start.root[0].root), JSON.stringify(attributes)); + + assert.equal(newJson.start.root[0].root.name, "anchor"); }); it("should create a bookmark with the correct attributes on the text element", () => { @@ -35,9 +32,6 @@ describe("Bookmark", () => { it("should create a bookmark with the correct attributes on the bookmark end element", () => { const newJson = Utility.jsonify(bookmark); - const attributes = { - id: "1", - }; - assert.equal(JSON.stringify(newJson.end.root[0].root), JSON.stringify(attributes)); + expect(newJson.end.root[0].root.id).to.be.a("string"); }); }); diff --git a/src/file/paragraph/links/bookmark.ts b/src/file/paragraph/links/bookmark.ts index c8c339e578..261a756864 100644 --- a/src/file/paragraph/links/bookmark.ts +++ b/src/file/paragraph/links/bookmark.ts @@ -1,49 +1,41 @@ // http://officeopenxml.com/WPbookmark.php import { XmlComponent } from "file/xml-components"; +import * as shortid from "shortid"; import { TextRun } from "../run"; import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; export class Bookmark { - public readonly linkId: number; public readonly start: BookmarkStart; public readonly text: TextRun; public readonly end: BookmarkEnd; - constructor(name: string, text: string, relationshipsCount: number) { - this.linkId = relationshipsCount + 1; + constructor(name: string, text: string) { + const linkId = shortid.generate().toLowerCase(); - this.start = new BookmarkStart(name, this.linkId); + this.start = new BookmarkStart(name, linkId); this.text = new TextRun(text); - this.end = new BookmarkEnd(this.linkId); + this.end = new BookmarkEnd(linkId); } } export class BookmarkStart extends XmlComponent { - public readonly linkId: number; - - constructor(name: string, relationshipsCount: number) { + constructor(name: string, linkId: string) { super("w:bookmarkStart"); - this.linkId = relationshipsCount; - const id = `${this.linkId}`; const attributes = new BookmarkStartAttributes({ name, - id, + id: linkId, }); this.root.push(attributes); } } export class BookmarkEnd extends XmlComponent { - public readonly linkId: number; - - constructor(relationshipsCount: number) { + constructor(linkId: string) { super("w:bookmarkEnd"); - this.linkId = relationshipsCount; - const id = `${this.linkId}`; const attributes = new BookmarkEndAttributes({ - id, + id: linkId, }); this.root.push(attributes); } diff --git a/src/file/paragraph/links/hyperlink.spec.ts b/src/file/paragraph/links/hyperlink.spec.ts index 09dd07b86f..50d6aa76aa 100644 --- a/src/file/paragraph/links/hyperlink.spec.ts +++ b/src/file/paragraph/links/hyperlink.spec.ts @@ -2,13 +2,20 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { Hyperlink } from "./"; +import { TextRun } from "../run"; +import { ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./hyperlink"; -describe("Hyperlink", () => { - let hyperlink: Hyperlink; +describe("ConcreteHyperlink", () => { + let hyperlink: ConcreteHyperlink; beforeEach(() => { - hyperlink = new Hyperlink("https://example.com", 0); + hyperlink = new ConcreteHyperlink( + new TextRun({ + text: "https://example.com", + style: "Hyperlink", + }), + "superid", + ); }); describe("#constructor()", () => { @@ -19,7 +26,7 @@ describe("Hyperlink", () => { { _attr: { "w:history": 1, - "r:id": "rId1", + "r:id": "rIdsuperid", }, }, { @@ -34,7 +41,14 @@ describe("Hyperlink", () => { describe("with optional anchor parameter", () => { beforeEach(() => { - hyperlink = new Hyperlink("Anchor Text", 0, "anchor"); + hyperlink = new ConcreteHyperlink( + new TextRun({ + text: "Anchor Text", + style: "Hyperlink", + }), + "superid2", + "anchor", + ); }); it("should create an internal link with anchor tag", () => { @@ -59,3 +73,54 @@ describe("Hyperlink", () => { }); }); }); + +describe("ExternalHyperlink", () => { + describe("#constructor()", () => { + it("should create", () => { + const externalHyperlink = new ExternalHyperlink({ + child: new TextRun("test"), + link: "http://www.google.com", + }); + + expect(externalHyperlink.options.link).to.equal("http://www.google.com"); + }); + }); +}); + +describe("InternalHyperlink", () => { + describe("#constructor()", () => { + it("should create", () => { + const internalHyperlink = new InternalHyperlink({ + child: new TextRun("test"), + anchor: "test-id", + }); + + const tree = new Formatter().format(internalHyperlink); + + expect(tree).to.deep.equal({ + "w:hyperlink": [ + { + _attr: { + "w:anchor": "test-id", + "w:history": 1, + }, + }, + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "test", + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/links/hyperlink.ts b/src/file/paragraph/links/hyperlink.ts index b41980ed77..a7512e7beb 100644 --- a/src/file/paragraph/links/hyperlink.ts +++ b/src/file/paragraph/links/hyperlink.ts @@ -1,16 +1,23 @@ // http://officeopenxml.com/WPhyperlink.php +import * as shortid from "shortid"; + import { XmlComponent } from "file/xml-components"; -import { TextRun } from "../run"; + +import { ParagraphChild } from "../paragraph"; import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes"; -export class Hyperlink extends XmlComponent { - public readonly linkId: number; - private readonly textRun: TextRun; +export enum HyperlinkType { + INTERNAL = "INTERNAL", + EXTERNAL = "EXTERNAL", +} - constructor(text: string, relationshipsCount: number, anchor?: string) { +export class ConcreteHyperlink extends XmlComponent { + public readonly linkId: string; + + constructor(child: ParagraphChild, relationshipId: string, anchor?: string) { super("w:hyperlink"); - this.linkId = relationshipsCount + 1; + this.linkId = relationshipId; const props: IHyperlinkAttributesProperties = { history: 1, @@ -20,14 +27,16 @@ export class Hyperlink extends XmlComponent { const attributes = new HyperlinkAttributes(props); this.root.push(attributes); - this.textRun = new TextRun({ - text: text, - style: "Hyperlink", - }); - this.root.push(this.textRun); - } - - public get TextRun(): TextRun { - return this.textRun; + this.root.push(child); } } + +export class InternalHyperlink extends ConcreteHyperlink { + constructor(options: { readonly child: ParagraphChild; readonly anchor: string }) { + super(options.child, shortid.generate().toLowerCase(), options.anchor); + } +} + +export class ExternalHyperlink { + constructor(public readonly options: { readonly child: ParagraphChild; readonly link: string }) {} +} diff --git a/src/file/paragraph/math/brackets/index.ts b/src/file/paragraph/math/brackets/index.ts new file mode 100644 index 0000000000..e6559cde29 --- /dev/null +++ b/src/file/paragraph/math/brackets/index.ts @@ -0,0 +1,4 @@ +export * from "./math-round-brackets"; +export * from "./math-square-brackets"; +export * from "./math-curly-brackets"; +export * from "./math-angled-brackets"; diff --git a/src/file/paragraph/math/brackets/math-angled-brackets.spec.ts b/src/file/paragraph/math/brackets/math-angled-brackets.spec.ts new file mode 100644 index 0000000000..ccd73b192b --- /dev/null +++ b/src/file/paragraph/math/brackets/math-angled-brackets.spec.ts @@ -0,0 +1,51 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathAngledBrackets } from "./math-angled-brackets"; + +describe("MathAngledBrackets", () => { + describe("#constructor()", () => { + it("should create a MathAngledBrackets with correct root key", () => { + const mathAngledBrackets = new MathAngledBrackets({ + children: [new MathRun("60")], + }); + + const tree = new Formatter().format(mathAngledBrackets); + expect(tree).to.deep.equal({ + "m:d": [ + { + "m:dPr": [ + { + "m:begChr": { + _attr: { + "m:val": "〈", + }, + }, + }, + { + "m:endChr": { + _attr: { + "m:val": "〉", + }, + }, + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["60"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-angled-brackets.ts b/src/file/paragraph/math/brackets/math-angled-brackets.ts new file mode 100644 index 0000000000..48fe0d415d --- /dev/null +++ b/src/file/paragraph/math/brackets/math-angled-brackets.ts @@ -0,0 +1,20 @@ +// http://www.datypic.com/sc/ooxml/e-m_d-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathBracketProperties } from "./math-bracket-properties"; + +export class MathAngledBrackets extends XmlComponent { + constructor(options: { readonly children: MathComponent[] }) { + super("m:d"); + + this.root.push( + new MathBracketProperties({ + beginningCharacter: "〈", + endingCharacter: "〉", + }), + ); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/brackets/math-beginning-character.spec.ts b/src/file/paragraph/math/brackets/math-beginning-character.spec.ts new file mode 100644 index 0000000000..bf9196c0a9 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-beginning-character.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathBeginningCharacter } from "./math-beginning-character"; + +describe("MathBeginningCharacter", () => { + describe("#constructor()", () => { + it("should create a MathBeginningCharacter with correct root key", () => { + const mathBeginningCharacter = new MathBeginningCharacter("["); + + const tree = new Formatter().format(mathBeginningCharacter); + expect(tree).to.deep.equal({ + "m:begChr": { + _attr: { + "m:val": "[", + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-beginning-character.ts b/src/file/paragraph/math/brackets/math-beginning-character.ts new file mode 100644 index 0000000000..aa9e06d87a --- /dev/null +++ b/src/file/paragraph/math/brackets/math-beginning-character.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_begChr-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathBeginningCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> { + protected readonly xmlKeys = { character: "m:val" }; +} + +export class MathBeginningCharacter extends XmlComponent { + constructor(character: string) { + super("m:begChr"); + + this.root.push(new MathBeginningCharacterAttributes({ character })); + } +} diff --git a/src/file/paragraph/math/brackets/math-bracket-properties.spec.ts b/src/file/paragraph/math/brackets/math-bracket-properties.spec.ts new file mode 100644 index 0000000000..d80976d8f6 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-bracket-properties.spec.ts @@ -0,0 +1,45 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathBracketProperties } from "./math-bracket-properties"; + +describe("MathBracketProperties", () => { + describe("#constructor()", () => { + it("should create a MathBracketProperties with correct root key", () => { + const mathBracketProperties = new MathBracketProperties(); + + const tree = new Formatter().format(mathBracketProperties); + expect(tree).to.deep.equal({ + "m:dPr": {}, + }); + }); + + it("should create a MathBracketProperties with correct root key and add brackets", () => { + const mathBracketProperties = new MathBracketProperties({ + beginningCharacter: "[", + endingCharacter: "]", + }); + + const tree = new Formatter().format(mathBracketProperties); + expect(tree).to.deep.equal({ + "m:dPr": [ + { + "m:begChr": { + _attr: { + "m:val": "[", + }, + }, + }, + { + "m:endChr": { + _attr: { + "m:val": "]", + }, + }, + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-bracket-properties.ts b/src/file/paragraph/math/brackets/math-bracket-properties.ts new file mode 100644 index 0000000000..5bba7bf935 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-bracket-properties.ts @@ -0,0 +1,16 @@ +// http://www.datypic.com/sc/ooxml/e-m_dPr-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathBeginningCharacter } from "./math-beginning-character"; +import { MathEndingCharacter } from "./math-ending-char"; + +export class MathBracketProperties extends XmlComponent { + constructor(options?: { readonly beginningCharacter: string; readonly endingCharacter: string }) { + super("m:dPr"); + + if (!!options) { + this.root.push(new MathBeginningCharacter(options.beginningCharacter)); + this.root.push(new MathEndingCharacter(options.endingCharacter)); + } + } +} diff --git a/src/file/paragraph/math/brackets/math-curly-brackets.spec.ts b/src/file/paragraph/math/brackets/math-curly-brackets.spec.ts new file mode 100644 index 0000000000..d6defd57ef --- /dev/null +++ b/src/file/paragraph/math/brackets/math-curly-brackets.spec.ts @@ -0,0 +1,51 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathCurlyBrackets } from "./math-curly-brackets"; + +describe("MathCurlyBrackets", () => { + describe("#constructor()", () => { + it("should create a MathCurlyBrackets with correct root key", () => { + const mathCurlyBrackets = new MathCurlyBrackets({ + children: [new MathRun("60")], + }); + + const tree = new Formatter().format(mathCurlyBrackets); + expect(tree).to.deep.equal({ + "m:d": [ + { + "m:dPr": [ + { + "m:begChr": { + _attr: { + "m:val": "{", + }, + }, + }, + { + "m:endChr": { + _attr: { + "m:val": "}", + }, + }, + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["60"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-curly-brackets.ts b/src/file/paragraph/math/brackets/math-curly-brackets.ts new file mode 100644 index 0000000000..ccce71e6a7 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-curly-brackets.ts @@ -0,0 +1,20 @@ +// http://www.datypic.com/sc/ooxml/e-m_d-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathBracketProperties } from "./math-bracket-properties"; + +export class MathCurlyBrackets extends XmlComponent { + constructor(options: { readonly children: MathComponent[] }) { + super("m:d"); + + this.root.push( + new MathBracketProperties({ + beginningCharacter: "{", + endingCharacter: "}", + }), + ); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/brackets/math-ending-char.ts b/src/file/paragraph/math/brackets/math-ending-char.ts new file mode 100644 index 0000000000..86d0a0a58c --- /dev/null +++ b/src/file/paragraph/math/brackets/math-ending-char.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_endChr-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathEndingCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> { + protected readonly xmlKeys = { character: "m:val" }; +} + +export class MathEndingCharacter extends XmlComponent { + constructor(character: string) { + super("m:endChr"); + + this.root.push(new MathEndingCharacterAttributes({ character })); + } +} diff --git a/src/file/paragraph/math/brackets/math-ending-character.spec.ts b/src/file/paragraph/math/brackets/math-ending-character.spec.ts new file mode 100644 index 0000000000..ba28ac7840 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-ending-character.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathEndingCharacter } from "./math-ending-char"; + +describe("MathEndingCharacter", () => { + describe("#constructor()", () => { + it("should create a MathEndingCharacter with correct root key", () => { + const mathEndingCharacter = new MathEndingCharacter("]"); + + const tree = new Formatter().format(mathEndingCharacter); + expect(tree).to.deep.equal({ + "m:endChr": { + _attr: { + "m:val": "]", + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-round-brackets.spec.ts b/src/file/paragraph/math/brackets/math-round-brackets.spec.ts new file mode 100644 index 0000000000..5138e9d085 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-round-brackets.spec.ts @@ -0,0 +1,36 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathRoundBrackets } from "./math-round-brackets"; + +describe("MathRoundBrackets", () => { + describe("#constructor()", () => { + it("should create a MathRoundBrackets with correct root key", () => { + const mathRoundBrackets = new MathRoundBrackets({ + children: [new MathRun("60")], + }); + + const tree = new Formatter().format(mathRoundBrackets); + expect(tree).to.deep.equal({ + "m:d": [ + { + "m:dPr": {}, + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["60"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-round-brackets.ts b/src/file/paragraph/math/brackets/math-round-brackets.ts new file mode 100644 index 0000000000..6fe60318a4 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-round-brackets.ts @@ -0,0 +1,15 @@ +// http://www.datypic.com/sc/ooxml/e-m_d-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathBracketProperties } from "./math-bracket-properties"; + +export class MathRoundBrackets extends XmlComponent { + constructor(options: { readonly children: MathComponent[] }) { + super("m:d"); + + this.root.push(new MathBracketProperties()); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/brackets/math-square-brackets.spec.ts b/src/file/paragraph/math/brackets/math-square-brackets.spec.ts new file mode 100644 index 0000000000..b0e2ec9e26 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-square-brackets.spec.ts @@ -0,0 +1,51 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathSquareBrackets } from "./math-square-brackets"; + +describe("MathSquareBrackets", () => { + describe("#constructor()", () => { + it("should create a MathSquareBrackets with correct root key", () => { + const mathSquareBrackets = new MathSquareBrackets({ + children: [new MathRun("60")], + }); + + const tree = new Formatter().format(mathSquareBrackets); + expect(tree).to.deep.equal({ + "m:d": [ + { + "m:dPr": [ + { + "m:begChr": { + _attr: { + "m:val": "[", + }, + }, + }, + { + "m:endChr": { + _attr: { + "m:val": "]", + }, + }, + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["60"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/brackets/math-square-brackets.ts b/src/file/paragraph/math/brackets/math-square-brackets.ts new file mode 100644 index 0000000000..fdfe88a004 --- /dev/null +++ b/src/file/paragraph/math/brackets/math-square-brackets.ts @@ -0,0 +1,20 @@ +// http://www.datypic.com/sc/ooxml/e-m_d-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathBracketProperties } from "./math-bracket-properties"; + +export class MathSquareBrackets extends XmlComponent { + constructor(options: { readonly children: MathComponent[] }) { + super("m:d"); + + this.root.push( + new MathBracketProperties({ + beginningCharacter: "[", + endingCharacter: "]", + }), + ); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/fraction/index.ts b/src/file/paragraph/math/fraction/index.ts new file mode 100644 index 0000000000..c8af438329 --- /dev/null +++ b/src/file/paragraph/math/fraction/index.ts @@ -0,0 +1,3 @@ +export * from "./math-fraction"; +export * from "./math-denominator"; +export * from "./math-numerator"; diff --git a/src/file/paragraph/math/fraction/math-denominator.spec.ts b/src/file/paragraph/math/fraction/math-denominator.spec.ts new file mode 100644 index 0000000000..f2e7459e1e --- /dev/null +++ b/src/file/paragraph/math/fraction/math-denominator.spec.ts @@ -0,0 +1,26 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathDenominator } from "./math-denominator"; + +describe("MathDenominator", () => { + describe("#constructor()", () => { + it("should create a MathDenominator with correct root key", () => { + const mathDenominator = new MathDenominator([new MathRun("2+2")]); + const tree = new Formatter().format(mathDenominator); + expect(tree).to.deep.equal({ + "m:den": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/fraction/math-denominator.ts b/src/file/paragraph/math/fraction/math-denominator.ts new file mode 100644 index 0000000000..8df68bf4b0 --- /dev/null +++ b/src/file/paragraph/math/fraction/math-denominator.ts @@ -0,0 +1,13 @@ +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; + +export class MathDenominator extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:den"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/fraction/math-fraction.spec.ts b/src/file/paragraph/math/fraction/math-fraction.spec.ts new file mode 100644 index 0000000000..51cac646bf --- /dev/null +++ b/src/file/paragraph/math/fraction/math-fraction.spec.ts @@ -0,0 +1,44 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathFraction } from "./math-fraction"; + +describe("MathFraction", () => { + describe("#constructor()", () => { + it("should create a MathFraction with correct root key", () => { + const mathFraction = new MathFraction({ + numerator: [new MathRun("2")], + denominator: [new MathRun("2")], + }); + const tree = new Formatter().format(mathFraction); + expect(tree).to.deep.equal({ + "m:f": [ + { + "m:num": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + { + "m:den": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/fraction/math-fraction.ts b/src/file/paragraph/math/fraction/math-fraction.ts new file mode 100644 index 0000000000..84a803a872 --- /dev/null +++ b/src/file/paragraph/math/fraction/math-fraction.ts @@ -0,0 +1,19 @@ +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathDenominator } from "./math-denominator"; +import { MathNumerator } from "./math-numerator"; + +export interface IMathFractionOptions { + readonly numerator: MathComponent[]; + readonly denominator: MathComponent[]; +} + +export class MathFraction extends XmlComponent { + constructor(options: IMathFractionOptions) { + super("m:f"); + + this.root.push(new MathNumerator(options.numerator)); + this.root.push(new MathDenominator(options.denominator)); + } +} diff --git a/src/file/paragraph/math/fraction/math-numerator.spec.ts b/src/file/paragraph/math/fraction/math-numerator.spec.ts new file mode 100644 index 0000000000..e3aaf35c0e --- /dev/null +++ b/src/file/paragraph/math/fraction/math-numerator.spec.ts @@ -0,0 +1,26 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathNumerator } from "./math-numerator"; + +describe("MathNumerator", () => { + describe("#constructor()", () => { + it("should create a MathNumerator with correct root key", () => { + const mathNumerator = new MathNumerator([new MathRun("2+2")]); + const tree = new Formatter().format(mathNumerator); + expect(tree).to.deep.equal({ + "m:num": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/fraction/math-numerator.ts b/src/file/paragraph/math/fraction/math-numerator.ts new file mode 100644 index 0000000000..b7a49d9a75 --- /dev/null +++ b/src/file/paragraph/math/fraction/math-numerator.ts @@ -0,0 +1,13 @@ +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; + +export class MathNumerator extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:num"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/function/index.ts b/src/file/paragraph/math/function/index.ts new file mode 100644 index 0000000000..58243c2710 --- /dev/null +++ b/src/file/paragraph/math/function/index.ts @@ -0,0 +1,3 @@ +export * from "./math-function"; +export * from "./math-function-name"; +export * from "./math-function-properties"; diff --git a/src/file/paragraph/math/function/math-function-name.spec.ts b/src/file/paragraph/math/function/math-function-name.spec.ts new file mode 100644 index 0000000000..8a37ee998e --- /dev/null +++ b/src/file/paragraph/math/function/math-function-name.spec.ts @@ -0,0 +1,27 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathFunctionName } from "./math-function-name"; + +describe("MathFunctionName", () => { + describe("#constructor()", () => { + it("should create a MathFunctionName with correct root key", () => { + const mathFunctionName = new MathFunctionName([new MathRun("2")]); + + const tree = new Formatter().format(mathFunctionName); + expect(tree).to.deep.equal({ + "m:fName": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/function/math-function-name.ts b/src/file/paragraph/math/function/math-function-name.ts new file mode 100644 index 0000000000..e58488dd28 --- /dev/null +++ b/src/file/paragraph/math/function/math-function-name.ts @@ -0,0 +1,13 @@ +// http://www.datypic.com/sc/ooxml/e-m_fName-1.html +import { XmlComponent } from "file/xml-components"; +import { MathComponent } from "../math-component"; + +export class MathFunctionName extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:fName"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/function/math-function-properties.spec.ts b/src/file/paragraph/math/function/math-function-properties.spec.ts new file mode 100644 index 0000000000..63ec2e4f60 --- /dev/null +++ b/src/file/paragraph/math/function/math-function-properties.spec.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathFunctionProperties } from "./math-function-properties"; + +describe("MathFunctionProperties", () => { + describe("#constructor()", () => { + it("should create a MathFunctionProperties with correct root key", () => { + const mathFunctionProperties = new MathFunctionProperties(); + + const tree = new Formatter().format(mathFunctionProperties); + expect(tree).to.deep.equal({ + "m:funcPr": {}, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/function/math-function-properties.ts b/src/file/paragraph/math/function/math-function-properties.ts new file mode 100644 index 0000000000..f6e8d608ac --- /dev/null +++ b/src/file/paragraph/math/function/math-function-properties.ts @@ -0,0 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-m_radPr-1.html +import { XmlComponent } from "file/xml-components"; + +export class MathFunctionProperties extends XmlComponent { + constructor() { + super("m:funcPr"); + } +} diff --git a/src/file/paragraph/math/function/math-function.spec.ts b/src/file/paragraph/math/function/math-function.spec.ts new file mode 100644 index 0000000000..6ea02b6c9d --- /dev/null +++ b/src/file/paragraph/math/function/math-function.spec.ts @@ -0,0 +1,48 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathFunction } from "./math-function"; + +describe("MathFunction", () => { + describe("#constructor()", () => { + it("should create a MathFunction with correct root key", () => { + const mathFunction = new MathFunction({ + name: [new MathRun("sin")], + children: [new MathRun("60")], + }); + + const tree = new Formatter().format(mathFunction); + expect(tree).to.deep.equal({ + "m:func": [ + { + "m:funcPr": {}, + }, + { + "m:fName": [ + { + "m:r": [ + { + "m:t": ["sin"], + }, + ], + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["60"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/function/math-function.ts b/src/file/paragraph/math/function/math-function.ts new file mode 100644 index 0000000000..86b66392cc --- /dev/null +++ b/src/file/paragraph/math/function/math-function.ts @@ -0,0 +1,22 @@ +// http://www.datypic.com/sc/ooxml/e-m_func-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathFunctionName } from "./math-function-name"; +import { MathFunctionProperties } from "./math-function-properties"; + +export interface IMathFunctionOptions { + readonly children: MathComponent[]; + readonly name: MathComponent[]; +} + +export class MathFunction extends XmlComponent { + constructor(options: IMathFunctionOptions) { + super("m:func"); + + this.root.push(new MathFunctionProperties()); + this.root.push(new MathFunctionName(options.name)); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/index.ts b/src/file/paragraph/math/index.ts new file mode 100644 index 0000000000..b42ec908f6 --- /dev/null +++ b/src/file/paragraph/math/index.ts @@ -0,0 +1,9 @@ +export * from "./math"; +export * from "./math-run"; +export * from "./fraction"; +export * from "./n-ary"; +export * from "./script"; +export * from "./math-component"; +export * from "./radical"; +export * from "./function"; +export * from "./brackets"; diff --git a/src/file/paragraph/math/math-component.ts b/src/file/paragraph/math/math-component.ts new file mode 100644 index 0000000000..8251235455 --- /dev/null +++ b/src/file/paragraph/math/math-component.ts @@ -0,0 +1,27 @@ +import { MathAngledBrackets, MathCurlyBrackets, MathRoundBrackets, MathSquareBrackets } from "./brackets"; +import { MathFraction } from "./fraction"; +import { MathFunction } from "./function"; +import { MathRun } from "./math-run"; +import { MathSum } from "./n-ary"; +import { MathRadical } from "./radical"; +import { MathSubScript, MathSubSuperScript, MathSuperScript } from "./script"; + +export type MathComponent = + | MathRun + | MathFraction + | MathSum + | MathSuperScript + | MathSubScript + | MathSubSuperScript + | MathRadical + | MathFunction + | MathRoundBrackets + | MathCurlyBrackets + | MathAngledBrackets + | MathSquareBrackets; + +// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432 +/** + * @ignore + */ +export const WORKAROUND4 = ""; diff --git a/src/file/paragraph/math/math-run.spec.ts b/src/file/paragraph/math/math-run.spec.ts new file mode 100644 index 0000000000..2773a0fb9c --- /dev/null +++ b/src/file/paragraph/math/math-run.spec.ts @@ -0,0 +1,21 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "./math-run"; + +describe("MathRun", () => { + describe("#constructor()", () => { + it("should create a MathRun with correct root key", () => { + const mathRun = new MathRun("2+2"); + const tree = new Formatter().format(mathRun); + expect(tree).to.deep.equal({ + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/math-run.ts b/src/file/paragraph/math/math-run.ts new file mode 100644 index 0000000000..0d2c48910f --- /dev/null +++ b/src/file/paragraph/math/math-run.ts @@ -0,0 +1,12 @@ +// http://www.datypic.com/sc/ooxml/e-m_r-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathText } from "./math-text"; + +export class MathRun extends XmlComponent { + constructor(text: string) { + super("m:r"); + + this.root.push(new MathText(text)); + } +} diff --git a/src/file/paragraph/math/math-text.spec.ts b/src/file/paragraph/math/math-text.spec.ts new file mode 100644 index 0000000000..0001816ed1 --- /dev/null +++ b/src/file/paragraph/math/math-text.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathText } from "./math-text"; + +describe("MathText", () => { + describe("#constructor()", () => { + it("should create a MathText with correct root key", () => { + const mathText = new MathText("2+2"); + const tree = new Formatter().format(mathText); + expect(tree).to.deep.equal({ + "m:t": ["2+2"], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/math-text.ts b/src/file/paragraph/math/math-text.ts new file mode 100644 index 0000000000..6087c7e611 --- /dev/null +++ b/src/file/paragraph/math/math-text.ts @@ -0,0 +1,9 @@ +import { XmlComponent } from "file/xml-components"; + +export class MathText extends XmlComponent { + constructor(text: string) { + super("m:t"); + + this.root.push(text); + } +} diff --git a/src/file/paragraph/math/math.spec.ts b/src/file/paragraph/math/math.spec.ts new file mode 100644 index 0000000000..d5c4f6f494 --- /dev/null +++ b/src/file/paragraph/math/math.spec.ts @@ -0,0 +1,38 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { Math } from "./math"; +import { MathRun } from "./math-run"; + +describe("Math", () => { + describe("#constructor()", () => { + it("should create a Math with correct root key", () => { + const math = new Math({ + children: [], + }); + const tree = new Formatter().format(math); + expect(tree).to.deep.equal({ + "m:oMath": {}, + }); + }); + + it("should be able to add children", () => { + const math = new Math({ + children: [new MathRun("2+2")], + }); + const tree = new Formatter().format(math); + expect(tree).to.deep.equal({ + "m:oMath": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/math.ts b/src/file/paragraph/math/math.ts new file mode 100644 index 0000000000..69ebae4dff --- /dev/null +++ b/src/file/paragraph/math/math.ts @@ -0,0 +1,18 @@ +// http://www.datypic.com/sc/ooxml/e-m_oMath-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "./math-component"; + +export interface IMathOptions { + readonly children: MathComponent[]; +} + +export class Math extends XmlComponent { + constructor(options: IMathOptions) { + super("m:oMath"); + + for (const child of options.children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/n-ary/index.ts b/src/file/paragraph/math/n-ary/index.ts new file mode 100644 index 0000000000..6929544152 --- /dev/null +++ b/src/file/paragraph/math/n-ary/index.ts @@ -0,0 +1,7 @@ +export * from "./math-accent-character"; +export * from "./math-base"; +export * from "./math-limit-location"; +export * from "./math-naray-properties"; +export * from "./math-sub-script"; +export * from "./math-sum"; +export * from "./math-super-script"; diff --git a/src/file/paragraph/math/n-ary/math-accent-character.spec.ts b/src/file/paragraph/math/n-ary/math-accent-character.spec.ts new file mode 100644 index 0000000000..b414f4c744 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-accent-character.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathAccentCharacter } from "./math-accent-character"; + +describe("MathAccentCharacter", () => { + describe("#constructor()", () => { + it("should create a MathAccentCharacter with correct root key", () => { + const mathAccentCharacter = new MathAccentCharacter("∑"); + + const tree = new Formatter().format(mathAccentCharacter); + expect(tree).to.deep.equal({ + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-accent-character.ts b/src/file/paragraph/math/n-ary/math-accent-character.ts new file mode 100644 index 0000000000..00182bd1f2 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-accent-character.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_chr-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathAccentCharacterAttributes extends XmlAttributeComponent<{ readonly accent: string }> { + protected readonly xmlKeys = { accent: "m:val" }; +} + +export class MathAccentCharacter extends XmlComponent { + constructor(accent: string) { + super("m:chr"); + + this.root.push(new MathAccentCharacterAttributes({ accent })); + } +} diff --git a/src/file/paragraph/math/n-ary/math-base.spec.ts b/src/file/paragraph/math/n-ary/math-base.spec.ts new file mode 100644 index 0000000000..c282537970 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-base.spec.ts @@ -0,0 +1,27 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathBase } from "./math-base"; + +describe("MathBase", () => { + describe("#constructor()", () => { + it("should create a MathBase with correct root key", () => { + const mathBase = new MathBase([new MathRun("2+2")]); + + const tree = new Formatter().format(mathBase); + expect(tree).to.deep.equal({ + "m:e": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-base.ts b/src/file/paragraph/math/n-ary/math-base.ts new file mode 100644 index 0000000000..6c2320439f --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-base.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_e-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; + +export class MathBase extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:e"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/n-ary/math-limit-location.spec.ts b/src/file/paragraph/math/n-ary/math-limit-location.spec.ts new file mode 100644 index 0000000000..426f3d0198 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-limit-location.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathLimitLocation } from "./math-limit-location"; + +describe("MathLimitLocation", () => { + describe("#constructor()", () => { + it("should create a MathLimitLocation with correct root key", () => { + const mathLimitLocation = new MathLimitLocation(); + + const tree = new Formatter().format(mathLimitLocation); + expect(tree).to.deep.equal({ + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-limit-location.ts b/src/file/paragraph/math/n-ary/math-limit-location.ts new file mode 100644 index 0000000000..5504e1890d --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-limit-location.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_limLoc-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathLimitLocationAttributes extends XmlAttributeComponent<{ readonly value: string }> { + protected readonly xmlKeys = { value: "m:val" }; +} + +export class MathLimitLocation extends XmlComponent { + constructor() { + super("m:limLoc"); + + this.root.push(new MathLimitLocationAttributes({ value: "undOvr" })); + } +} diff --git a/src/file/paragraph/math/n-ary/math-naray-properties.spec.ts b/src/file/paragraph/math/n-ary/math-naray-properties.spec.ts new file mode 100644 index 0000000000..70aa74a1c4 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-naray-properties.spec.ts @@ -0,0 +1,133 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathNArayProperties } from "./math-naray-properties"; + +describe("MathNArayProperties", () => { + describe("#constructor()", () => { + it("should create a MathNArayProperties with correct root key", () => { + const mathNArayProperties = new MathNArayProperties("∑", true, true); + + const tree = new Formatter().format(mathNArayProperties); + expect(tree).to.deep.equal({ + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + ], + }); + }); + + it("should add super-script hide attributes", () => { + const mathNArayProperties = new MathNArayProperties("∑", false, true); + + const tree = new Formatter().format(mathNArayProperties); + expect(tree).to.deep.equal({ + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + { + "m:supHide": { + _attr: { + "m:val": 1, + }, + }, + }, + ], + }); + }); + + it("should add sub-script hide attributes", () => { + const mathNArayProperties = new MathNArayProperties("∑", true, false); + + const tree = new Formatter().format(mathNArayProperties); + expect(tree).to.deep.equal({ + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + { + "m:subHide": { + _attr: { + "m:val": 1, + }, + }, + }, + ], + }); + }); + + it("should add both super-script and sub-script hide attributes", () => { + const mathNArayProperties = new MathNArayProperties("∑", false, false); + + const tree = new Formatter().format(mathNArayProperties); + expect(tree).to.deep.equal({ + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + { + "m:supHide": { + _attr: { + "m:val": 1, + }, + }, + }, + { + "m:subHide": { + _attr: { + "m:val": 1, + }, + }, + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-naray-properties.ts b/src/file/paragraph/math/n-ary/math-naray-properties.ts new file mode 100644 index 0000000000..f8e91e746a --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-naray-properties.ts @@ -0,0 +1,24 @@ +// http://www.datypic.com/sc/ooxml/e-m_naryPr-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathAccentCharacter } from "./math-accent-character"; +import { MathLimitLocation } from "./math-limit-location"; +import { MathSubScriptHide } from "./math-sub-script-hide"; +import { MathSuperScriptHide } from "./math-super-script-hide"; + +export class MathNArayProperties extends XmlComponent { + constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean) { + super("m:naryPr"); + + this.root.push(new MathAccentCharacter(accent)); + this.root.push(new MathLimitLocation()); + + if (!hasSuperScript) { + this.root.push(new MathSuperScriptHide()); + } + + if (!hasSubScript) { + this.root.push(new MathSubScriptHide()); + } + } +} diff --git a/src/file/paragraph/math/n-ary/math-sub-script-hide.spec.ts b/src/file/paragraph/math/n-ary/math-sub-script-hide.spec.ts new file mode 100644 index 0000000000..2e9845172f --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sub-script-hide.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathSubScriptHide } from "./math-sub-script-hide"; + +describe("MathSubScriptHide", () => { + describe("#constructor()", () => { + it("should create a MathSubScriptHide with correct root key", () => { + const mathSubScriptHide = new MathSubScriptHide(); + + const tree = new Formatter().format(mathSubScriptHide); + expect(tree).to.deep.equal({ + "m:subHide": { + _attr: { + "m:val": 1, + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-sub-script-hide.ts b/src/file/paragraph/math/n-ary/math-sub-script-hide.ts new file mode 100644 index 0000000000..ef735744e0 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sub-script-hide.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathSubScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> { + protected readonly xmlKeys = { hide: "m:val" }; +} + +export class MathSubScriptHide extends XmlComponent { + constructor() { + super("m:subHide"); + + this.root.push(new MathSubScriptHideAttributes({ hide: 1 })); + } +} diff --git a/src/file/paragraph/math/n-ary/math-sub-script.spec.ts b/src/file/paragraph/math/n-ary/math-sub-script.spec.ts new file mode 100644 index 0000000000..d342946b74 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sub-script.spec.ts @@ -0,0 +1,27 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathSubScriptElement } from "./math-sub-script"; + +describe("MathSubScriptElement", () => { + describe("#constructor()", () => { + it("should create a MathSubScriptElement with correct root key", () => { + const mathSubScriptElement = new MathSubScriptElement([new MathRun("2+2")]); + + const tree = new Formatter().format(mathSubScriptElement); + expect(tree).to.deep.equal({ + "m:sub": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-sub-script.ts b/src/file/paragraph/math/n-ary/math-sub-script.ts new file mode 100644 index 0000000000..48268312cf --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sub-script.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_sub-3.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; + +export class MathSubScriptElement extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:sub"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/n-ary/math-sum.spec.ts b/src/file/paragraph/math/n-ary/math-sum.spec.ts new file mode 100644 index 0000000000..9a7cbbaaa2 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sum.spec.ts @@ -0,0 +1,130 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathSum } from "./math-sum"; + +describe("MathSum", () => { + describe("#constructor()", () => { + it("should create a MathSum with correct root key", () => { + const mathSum = new MathSum({ + children: [new MathRun("1")], + subScript: [new MathRun("2")], + superScript: [new MathRun("3")], + }); + + const tree = new Formatter().format(mathSum); + expect(tree).to.deep.equal({ + "m:nary": [ + { + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + ], + }, + { + "m:sub": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + { + "m:sup": [ + { + "m:r": [ + { + "m:t": ["3"], + }, + ], + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["1"], + }, + ], + }, + ], + }, + ], + }); + }); + + it("should add a hide when there is no subScript or superScript", () => { + const mathSum = new MathSum({ + children: [new MathRun("1")], + }); + + const tree = new Formatter().format(mathSum); + expect(tree).to.deep.equal({ + "m:nary": [ + { + "m:naryPr": [ + { + "m:chr": { + _attr: { + "m:val": "∑", + }, + }, + }, + { + "m:limLoc": { + _attr: { + "m:val": "undOvr", + }, + }, + }, + { + "m:supHide": { + _attr: { + "m:val": 1, + }, + }, + }, + { + "m:subHide": { + _attr: { + "m:val": 1, + }, + }, + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["1"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-sum.ts b/src/file/paragraph/math/n-ary/math-sum.ts new file mode 100644 index 0000000000..af14730bbf --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-sum.ts @@ -0,0 +1,32 @@ +// http://www.datypic.com/sc/ooxml/e-m_nary-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "./math-base"; +import { MathNArayProperties } from "./math-naray-properties"; +import { MathSubScriptElement } from "./math-sub-script"; +import { MathSuperScriptElement } from "./math-super-script"; + +export interface IMathSumOptions { + readonly children: MathComponent[]; + readonly subScript?: MathComponent[]; + readonly superScript?: MathComponent[]; +} + +export class MathSum extends XmlComponent { + constructor(options: IMathSumOptions) { + super("m:nary"); + + this.root.push(new MathNArayProperties("∑", !!options.superScript, !!options.subScript)); + + if (!!options.subScript) { + this.root.push(new MathSubScriptElement(options.subScript)); + } + + if (!!options.superScript) { + this.root.push(new MathSuperScriptElement(options.superScript)); + } + + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/n-ary/math-super-script-hide.spec.ts b/src/file/paragraph/math/n-ary/math-super-script-hide.spec.ts new file mode 100644 index 0000000000..89a28564ac --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-super-script-hide.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathSuperScriptHide } from "./math-super-script-hide"; + +describe("MathSuperScriptHide", () => { + describe("#constructor()", () => { + it("should create a MathSuperScriptHide with correct root key", () => { + const mathSuperScriptHide = new MathSuperScriptHide(); + + const tree = new Formatter().format(mathSuperScriptHide); + expect(tree).to.deep.equal({ + "m:supHide": { + _attr: { + "m:val": 1, + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-super-script-hide.ts b/src/file/paragraph/math/n-ary/math-super-script-hide.ts new file mode 100644 index 0000000000..a55c15a7ad --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-super-script-hide.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathSuperScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> { + protected readonly xmlKeys = { hide: "m:val" }; +} + +export class MathSuperScriptHide extends XmlComponent { + constructor() { + super("m:supHide"); + + this.root.push(new MathSuperScriptHideAttributes({ hide: 1 })); + } +} diff --git a/src/file/paragraph/math/n-ary/math-super-script.spec.ts b/src/file/paragraph/math/n-ary/math-super-script.spec.ts new file mode 100644 index 0000000000..10e037eba3 --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-super-script.spec.ts @@ -0,0 +1,27 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathSuperScriptElement } from "./math-super-script"; + +describe("MathSuperScriptElement", () => { + describe("#constructor()", () => { + it("should create a MathSuperScriptElement with correct root key", () => { + const mathSuperScriptElement = new MathSuperScriptElement([new MathRun("2+2")]); + + const tree = new Formatter().format(mathSuperScriptElement); + expect(tree).to.deep.equal({ + "m:sup": [ + { + "m:r": [ + { + "m:t": ["2+2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/n-ary/math-super-script.ts b/src/file/paragraph/math/n-ary/math-super-script.ts new file mode 100644 index 0000000000..8d8386addc --- /dev/null +++ b/src/file/paragraph/math/n-ary/math-super-script.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_sup-3.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; + +export class MathSuperScriptElement extends XmlComponent { + constructor(children: MathComponent[]) { + super("m:sup"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/paragraph/math/radical/index.ts b/src/file/paragraph/math/radical/index.ts new file mode 100644 index 0000000000..78240ccd13 --- /dev/null +++ b/src/file/paragraph/math/radical/index.ts @@ -0,0 +1,3 @@ +export * from "./math-degree"; +export * from "./math-radical"; +export * from "./math-radical-properties"; diff --git a/src/file/paragraph/math/radical/math-degree-hide.spec.ts b/src/file/paragraph/math/radical/math-degree-hide.spec.ts new file mode 100644 index 0000000000..0c3f335a13 --- /dev/null +++ b/src/file/paragraph/math/radical/math-degree-hide.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathDegreeHide } from "./math-degree-hide"; + +describe("MathDegreeHide", () => { + describe("#constructor()", () => { + it("should create a MathDegreeHide with correct root key", () => { + const mathDegreeHide = new MathDegreeHide(); + + const tree = new Formatter().format(mathDegreeHide); + expect(tree).to.deep.equal({ + "m:degHide": { + _attr: { + "m:val": 1, + }, + }, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/radical/math-degree-hide.ts b/src/file/paragraph/math/radical/math-degree-hide.ts new file mode 100644 index 0000000000..c1b9dd2ae5 --- /dev/null +++ b/src/file/paragraph/math/radical/math-degree-hide.ts @@ -0,0 +1,14 @@ +// http://www.datypic.com/sc/ooxml/e-m_degHide-1.html +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class MathDegreeHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> { + protected readonly xmlKeys = { hide: "m:val" }; +} + +export class MathDegreeHide extends XmlComponent { + constructor() { + super("m:degHide"); + + this.root.push(new MathDegreeHideAttributes({ hide: 1 })); + } +} diff --git a/src/file/paragraph/math/radical/math-degree.spec.ts b/src/file/paragraph/math/radical/math-degree.spec.ts new file mode 100644 index 0000000000..3d1f17dfa8 --- /dev/null +++ b/src/file/paragraph/math/radical/math-degree.spec.ts @@ -0,0 +1,36 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathDegree } from "./math-degree"; + +describe("MathDegree", () => { + describe("#constructor()", () => { + it("should create a MathDegree with correct root key", () => { + const mathDegree = new MathDegree(); + + const tree = new Formatter().format(mathDegree); + expect(tree).to.deep.equal({ + "m:deg": {}, + }); + }); + + it("should create a MathDegree with correct root key with child", () => { + const mathDegree = new MathDegree([new MathRun("2")]); + + const tree = new Formatter().format(mathDegree); + expect(tree).to.deep.equal({ + "m:deg": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/radical/math-degree.ts b/src/file/paragraph/math/radical/math-degree.ts new file mode 100644 index 0000000000..79923bbde8 --- /dev/null +++ b/src/file/paragraph/math/radical/math-degree.ts @@ -0,0 +1,15 @@ +// http://www.datypic.com/sc/ooxml/e-m_deg-1.html +import { XmlComponent } from "file/xml-components"; +import { MathComponent } from "../math-component"; + +export class MathDegree extends XmlComponent { + constructor(children?: MathComponent[]) { + super("m:deg"); + + if (!!children) { + for (const child of children) { + this.root.push(child); + } + } + } +} diff --git a/src/file/paragraph/math/radical/math-radical-properties.spec.ts b/src/file/paragraph/math/radical/math-radical-properties.spec.ts new file mode 100644 index 0000000000..12d29a2962 --- /dev/null +++ b/src/file/paragraph/math/radical/math-radical-properties.spec.ts @@ -0,0 +1,35 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRadicalProperties } from "./math-radical-properties"; + +describe("MathRadicalProperties", () => { + describe("#constructor()", () => { + it("should create a MathRadicalProperties with correct root key", () => { + const mathRadicalProperties = new MathRadicalProperties(true); + + const tree = new Formatter().format(mathRadicalProperties); + expect(tree).to.deep.equal({ + "m:radPr": {}, + }); + }); + + it("should create a MathRadicalProperties with correct root key with degree hide", () => { + const mathRadicalProperties = new MathRadicalProperties(false); + + const tree = new Formatter().format(mathRadicalProperties); + expect(tree).to.deep.equal({ + "m:radPr": [ + { + "m:degHide": { + _attr: { + "m:val": 1, + }, + }, + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/radical/math-radical-properties.ts b/src/file/paragraph/math/radical/math-radical-properties.ts new file mode 100644 index 0000000000..b4e90ed4df --- /dev/null +++ b/src/file/paragraph/math/radical/math-radical-properties.ts @@ -0,0 +1,13 @@ +// http://www.datypic.com/sc/ooxml/e-m_radPr-1.html +import { XmlComponent } from "file/xml-components"; +import { MathDegreeHide } from "./math-degree-hide"; + +export class MathRadicalProperties extends XmlComponent { + constructor(hasDegree: boolean) { + super("m:radPr"); + + if (!hasDegree) { + this.root.push(new MathDegreeHide()); + } + } +} diff --git a/src/file/paragraph/math/radical/math-radical.spec.ts b/src/file/paragraph/math/radical/math-radical.spec.ts new file mode 100644 index 0000000000..e388edece4 --- /dev/null +++ b/src/file/paragraph/math/radical/math-radical.spec.ts @@ -0,0 +1,48 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../math-run"; +import { MathRadical } from "./math-radical"; + +describe("MathRadical", () => { + describe("#constructor()", () => { + it("should create a MathRadical with correct root key", () => { + const mathRadical = new MathRadical({ + children: [new MathRun("e")], + degree: [new MathRun("2")], + }); + + const tree = new Formatter().format(mathRadical); + expect(tree).to.deep.equal({ + "m:rad": [ + { + "m:radPr": {}, + }, + { + "m:deg": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["e"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/radical/math-radical.ts b/src/file/paragraph/math/radical/math-radical.ts new file mode 100644 index 0000000000..1469867a5f --- /dev/null +++ b/src/file/paragraph/math/radical/math-radical.ts @@ -0,0 +1,22 @@ +// http://www.datypic.com/sc/ooxml/e-m_rad-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../math-component"; +import { MathBase } from "../n-ary"; +import { MathDegree } from "./math-degree"; +import { MathRadicalProperties } from "./math-radical-properties"; + +export interface IMathRadicalOptions { + readonly children: MathComponent[]; + readonly degree?: MathComponent[]; +} + +export class MathRadical extends XmlComponent { + constructor(options: IMathRadicalOptions) { + super("m:rad"); + + this.root.push(new MathRadicalProperties(!!options.degree)); + this.root.push(new MathDegree(options.degree)); + this.root.push(new MathBase(options.children)); + } +} diff --git a/src/file/paragraph/math/script/index.ts b/src/file/paragraph/math/script/index.ts new file mode 100644 index 0000000000..a83e54975e --- /dev/null +++ b/src/file/paragraph/math/script/index.ts @@ -0,0 +1,4 @@ +export * from "./super-script"; +export * from "./sub-script"; +export * from "./sub-super-script"; +export * from "./pre-sub-super-script"; diff --git a/src/file/paragraph/math/script/pre-sub-super-script/index.ts b/src/file/paragraph/math/script/pre-sub-super-script/index.ts new file mode 100644 index 0000000000..8660a75017 --- /dev/null +++ b/src/file/paragraph/math/script/pre-sub-super-script/index.ts @@ -0,0 +1,2 @@ +export * from "./math-pre-sub-super-script-function"; +export * from "./math-pre-sub-super-script-function-properties"; diff --git a/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.spec.ts b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.spec.ts new file mode 100644 index 0000000000..a6f1d5383e --- /dev/null +++ b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { MathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties"; + +describe("MathPreSubSuperScriptProperties", () => { + describe("#constructor()", () => { + it("should create a MathPreSubSuperScriptProperties with correct root key", () => { + const mathPreSubSuperScriptProperties = new MathPreSubSuperScriptProperties(); + + const tree = new Formatter().format(mathPreSubSuperScriptProperties); + expect(tree).to.deep.equal({ + "m:sPrePr": {}, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.ts b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.ts new file mode 100644 index 0000000000..fed0cb3564 --- /dev/null +++ b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function-properties.ts @@ -0,0 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-m_sPrePr-1.html +import { XmlComponent } from "file/xml-components"; + +export class MathPreSubSuperScriptProperties extends XmlComponent { + constructor() { + super("m:sPrePr"); + } +} diff --git a/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.spec.ts b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.spec.ts new file mode 100644 index 0000000000..20d00a639d --- /dev/null +++ b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.spec.ts @@ -0,0 +1,60 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../../math-run"; +import { MathPreSubSuperScript } from "./math-pre-sub-super-script-function"; + +describe("MathPreSubScript", () => { + describe("#constructor()", () => { + it("should create a MathPreSubScript with correct root key", () => { + const mathPreSubScript = new MathPreSubSuperScript({ + children: [new MathRun("e")], + subScript: [new MathRun("2")], + superScript: [new MathRun("5")], + }); + + const tree = new Formatter().format(mathPreSubScript); + expect(tree).to.deep.equal({ + "m:sPre": [ + { + "m:sPrePr": {}, + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["e"], + }, + ], + }, + ], + }, + { + "m:sub": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + { + "m:sup": [ + { + "m:r": [ + { + "m:t": ["5"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.ts b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.ts new file mode 100644 index 0000000000..3a58675b0f --- /dev/null +++ b/src/file/paragraph/math/script/pre-sub-super-script/math-pre-sub-super-script-function.ts @@ -0,0 +1,23 @@ +// http://www.datypic.com/sc/ooxml/e-m_sPre-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../../math-component"; +import { MathBase, MathSubScriptElement, MathSuperScriptElement } from "../../n-ary"; +import { MathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties"; + +export interface IMathPreSubSuperScriptOptions { + readonly children: MathComponent[]; + readonly subScript: MathComponent[]; + readonly superScript: MathComponent[]; +} + +export class MathPreSubSuperScript extends XmlComponent { + constructor(options: IMathPreSubSuperScriptOptions) { + super("m:sPre"); + + this.root.push(new MathPreSubSuperScriptProperties()); + this.root.push(new MathBase(options.children)); + this.root.push(new MathSubScriptElement(options.subScript)); + this.root.push(new MathSuperScriptElement(options.superScript)); + } +} diff --git a/src/file/paragraph/math/script/sub-script/index.ts b/src/file/paragraph/math/script/sub-script/index.ts new file mode 100644 index 0000000000..0f1c27fe51 --- /dev/null +++ b/src/file/paragraph/math/script/sub-script/index.ts @@ -0,0 +1,2 @@ +export * from "./math-sub-script-function"; +export * from "./math-sub-script-function-properties"; diff --git a/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.spec.ts b/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.spec.ts new file mode 100644 index 0000000000..be229e066b --- /dev/null +++ b/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { MathSubScriptProperties } from "./math-sub-script-function-properties"; + +describe("MathSubScriptProperties", () => { + describe("#constructor()", () => { + it("should create a MathSubScriptProperties with correct root key", () => { + const mathSubScriptProperties = new MathSubScriptProperties(); + + const tree = new Formatter().format(mathSubScriptProperties); + expect(tree).to.deep.equal({ + "m:sSubPr": {}, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.ts b/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.ts new file mode 100644 index 0000000000..bf37b1d885 --- /dev/null +++ b/src/file/paragraph/math/script/sub-script/math-sub-script-function-properties.ts @@ -0,0 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSubPr-1.html +import { XmlComponent } from "file/xml-components"; + +export class MathSubScriptProperties extends XmlComponent { + constructor() { + super("m:sSubPr"); + } +} diff --git a/src/file/paragraph/math/script/sub-script/math-sub-script-function.spec.ts b/src/file/paragraph/math/script/sub-script/math-sub-script-function.spec.ts new file mode 100644 index 0000000000..a3ea8d680c --- /dev/null +++ b/src/file/paragraph/math/script/sub-script/math-sub-script-function.spec.ts @@ -0,0 +1,48 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../../math-run"; +import { MathSubScript } from "./math-sub-script-function"; + +describe("MathSubScript", () => { + describe("#constructor()", () => { + it("should create a MathSubScript with correct root key", () => { + const mathSubScript = new MathSubScript({ + children: [new MathRun("e")], + subScript: [new MathRun("2")], + }); + + const tree = new Formatter().format(mathSubScript); + expect(tree).to.deep.equal({ + "m:sSub": [ + { + "m:sSubPr": {}, + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["e"], + }, + ], + }, + ], + }, + { + "m:sub": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/sub-script/math-sub-script-function.ts b/src/file/paragraph/math/script/sub-script/math-sub-script-function.ts new file mode 100644 index 0000000000..319d4d1f1a --- /dev/null +++ b/src/file/paragraph/math/script/sub-script/math-sub-script-function.ts @@ -0,0 +1,21 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSub-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../../math-component"; +import { MathBase, MathSubScriptElement } from "../../n-ary"; +import { MathSubScriptProperties } from "./math-sub-script-function-properties"; + +export interface IMathSubScriptOptions { + readonly children: MathComponent[]; + readonly subScript: MathComponent[]; +} + +export class MathSubScript extends XmlComponent { + constructor(options: IMathSubScriptOptions) { + super("m:sSub"); + + this.root.push(new MathSubScriptProperties()); + this.root.push(new MathBase(options.children)); + this.root.push(new MathSubScriptElement(options.subScript)); + } +} diff --git a/src/file/paragraph/math/script/sub-super-script/index.ts b/src/file/paragraph/math/script/sub-super-script/index.ts new file mode 100644 index 0000000000..88ddeb69fa --- /dev/null +++ b/src/file/paragraph/math/script/sub-super-script/index.ts @@ -0,0 +1,2 @@ +export * from "./math-sub-super-script-function"; +export * from "./math-sub-super-script-function-properties"; diff --git a/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.spec.ts b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.spec.ts new file mode 100644 index 0000000000..b0f934823a --- /dev/null +++ b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { MathSubSuperScriptProperties } from "./math-sub-super-script-function-properties"; + +describe("MathSubSuperScriptProperties", () => { + describe("#constructor()", () => { + it("should create a MathSubSuperScriptProperties with correct root key", () => { + const mathSubSuperScriptProperties = new MathSubSuperScriptProperties(); + + const tree = new Formatter().format(mathSubSuperScriptProperties); + expect(tree).to.deep.equal({ + "m:sSubSupPr": {}, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.ts b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.ts new file mode 100644 index 0000000000..b3218a7d3a --- /dev/null +++ b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function-properties.ts @@ -0,0 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSubSupPr-1.html +import { XmlComponent } from "file/xml-components"; + +export class MathSubSuperScriptProperties extends XmlComponent { + constructor() { + super("m:sSubSupPr"); + } +} diff --git a/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.spec.ts b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.spec.ts new file mode 100644 index 0000000000..68a86fb26b --- /dev/null +++ b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.spec.ts @@ -0,0 +1,60 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../../math-run"; +import { MathSubSuperScript } from "./math-sub-super-script-function"; + +describe("MathSubScript", () => { + describe("#constructor()", () => { + it("should create a MathSubScript with correct root key", () => { + const mathSubScript = new MathSubSuperScript({ + children: [new MathRun("e")], + subScript: [new MathRun("2")], + superScript: [new MathRun("5")], + }); + + const tree = new Formatter().format(mathSubScript); + expect(tree).to.deep.equal({ + "m:sSubSup": [ + { + "m:sSubSupPr": {}, + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["e"], + }, + ], + }, + ], + }, + { + "m:sub": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + { + "m:sup": [ + { + "m:r": [ + { + "m:t": ["5"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.ts b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.ts new file mode 100644 index 0000000000..c382c9ff4c --- /dev/null +++ b/src/file/paragraph/math/script/sub-super-script/math-sub-super-script-function.ts @@ -0,0 +1,23 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSubSup-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../../math-component"; +import { MathBase, MathSubScriptElement, MathSuperScriptElement } from "../../n-ary"; +import { MathSubSuperScriptProperties } from "./math-sub-super-script-function-properties"; + +export interface IMathSubSuperScriptOptions { + readonly children: MathComponent[]; + readonly subScript: MathComponent[]; + readonly superScript: MathComponent[]; +} + +export class MathSubSuperScript extends XmlComponent { + constructor(options: IMathSubSuperScriptOptions) { + super("m:sSubSup"); + + this.root.push(new MathSubSuperScriptProperties()); + this.root.push(new MathBase(options.children)); + this.root.push(new MathSubScriptElement(options.subScript)); + this.root.push(new MathSuperScriptElement(options.superScript)); + } +} diff --git a/src/file/paragraph/math/script/super-script/index.ts b/src/file/paragraph/math/script/super-script/index.ts new file mode 100644 index 0000000000..2864fe9ac5 --- /dev/null +++ b/src/file/paragraph/math/script/super-script/index.ts @@ -0,0 +1,2 @@ +export * from "./math-super-script-function"; +export * from "./math-super-script-function-properties"; diff --git a/src/file/paragraph/math/script/super-script/math-super-script-function-properties.spec.ts b/src/file/paragraph/math/script/super-script/math-super-script-function-properties.spec.ts new file mode 100644 index 0000000000..f95920f152 --- /dev/null +++ b/src/file/paragraph/math/script/super-script/math-super-script-function-properties.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { MathSuperScriptProperties } from "./math-super-script-function-properties"; + +describe("MathSuperScriptProperties", () => { + describe("#constructor()", () => { + it("should create a MathSuperScriptProperties with correct root key", () => { + const mathSuperScriptProperties = new MathSuperScriptProperties(); + + const tree = new Formatter().format(mathSuperScriptProperties); + expect(tree).to.deep.equal({ + "m:sSupPr": {}, + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/super-script/math-super-script-function-properties.ts b/src/file/paragraph/math/script/super-script/math-super-script-function-properties.ts new file mode 100644 index 0000000000..ea5dbac20b --- /dev/null +++ b/src/file/paragraph/math/script/super-script/math-super-script-function-properties.ts @@ -0,0 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSupPr-1.html +import { XmlComponent } from "file/xml-components"; + +export class MathSuperScriptProperties extends XmlComponent { + constructor() { + super("m:sSupPr"); + } +} diff --git a/src/file/paragraph/math/script/super-script/math-super-script-function.spec.ts b/src/file/paragraph/math/script/super-script/math-super-script-function.spec.ts new file mode 100644 index 0000000000..ae3740360b --- /dev/null +++ b/src/file/paragraph/math/script/super-script/math-super-script-function.spec.ts @@ -0,0 +1,48 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { MathRun } from "../../math-run"; +import { MathSuperScript } from "./math-super-script-function"; + +describe("MathSuperScript", () => { + describe("#constructor()", () => { + it("should create a MathSuperScript with correct root key", () => { + const mathSuperScript = new MathSuperScript({ + children: [new MathRun("e")], + superScript: [new MathRun("2")], + }); + + const tree = new Formatter().format(mathSuperScript); + expect(tree).to.deep.equal({ + "m:sSup": [ + { + "m:sSupPr": {}, + }, + { + "m:e": [ + { + "m:r": [ + { + "m:t": ["e"], + }, + ], + }, + ], + }, + { + "m:sup": [ + { + "m:r": [ + { + "m:t": ["2"], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/math/script/super-script/math-super-script-function.ts b/src/file/paragraph/math/script/super-script/math-super-script-function.ts new file mode 100644 index 0000000000..eeffdf124a --- /dev/null +++ b/src/file/paragraph/math/script/super-script/math-super-script-function.ts @@ -0,0 +1,21 @@ +// http://www.datypic.com/sc/ooxml/e-m_sSup-1.html +import { XmlComponent } from "file/xml-components"; + +import { MathComponent } from "../../math-component"; +import { MathBase, MathSuperScriptElement } from "../../n-ary"; +import { MathSuperScriptProperties } from "./math-super-script-function-properties"; + +export interface IMathSuperScriptOptions { + readonly children: MathComponent[]; + readonly superScript: MathComponent[]; +} + +export class MathSuperScript extends XmlComponent { + constructor(options: IMathSuperScriptOptions) { + super("m:sSup"); + + this.root.push(new MathSuperScriptProperties()); + this.root.push(new MathBase(options.children)); + this.root.push(new MathSuperScriptElement(options.superScript)); + } +} diff --git a/src/file/paragraph/paragraph.spec.ts b/src/file/paragraph/paragraph.spec.ts index e8e5f6c8c9..4302801a01 100644 --- a/src/file/paragraph/paragraph.spec.ts +++ b/src/file/paragraph/paragraph.spec.ts @@ -1,11 +1,16 @@ import { assert, expect } from "chai"; +import * as shortid from "shortid"; +import { stub } from "sinon"; import { Formatter } from "export/formatter"; import { EMPTY_OBJECT } from "file/xml-components"; -import { Numbering } from "../numbering"; +import { IViewWrapper } from "../document-wrapper"; +import { ShadingType } from "../table/shading"; import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition, TabStopType } from "./formatting"; +import { Bookmark, ExternalHyperlink } from "./links"; import { Paragraph } from "./paragraph"; +import { TextRun } from "./run"; describe("Paragraph", () => { describe("#constructor()", () => { @@ -540,14 +545,8 @@ describe("Paragraph", () => { }, }); const tree = new Formatter().format(paragraph); - expect(tree) - .to.have.property("w:p") - .which.is.an("array") - .which.has.length.at.least(1); - expect(tree["w:p"][0]) - .to.have.property("w:pPr") - .which.is.an("array") - .which.has.length.at.least(1); + expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1); + expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1); expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({ "w:pStyle": { _attr: { "w:val": "ListParagraph" } }, }); @@ -560,14 +559,8 @@ describe("Paragraph", () => { }, }); const tree = new Formatter().format(paragraph); - expect(tree) - .to.have.property("w:p") - .which.is.an("array") - .which.has.length.at.least(1); - expect(tree["w:p"][0]) - .to.have.property("w:pPr") - .which.is.an("array") - .which.has.length.at.least(1); + expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1); + expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1); expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({ "w:pStyle": { _attr: { "w:val": "ListParagraph" } }, }); @@ -580,14 +573,8 @@ describe("Paragraph", () => { }, }); const tree = new Formatter().format(paragraph); - expect(tree) - .to.have.property("w:p") - .which.is.an("array") - .which.has.length.at.least(1); - expect(tree["w:p"][0]) - .to.have.property("w:pPr") - .which.is.an("array") - .which.has.length.at.least(2); + expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1); + expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(2); expect(tree["w:p"][0]["w:pPr"][1]).to.deep.equal({ "w:numPr": [{ "w:ilvl": { _attr: { "w:val": 1 } } }, { "w:numId": { _attr: { "w:val": 1 } } }], }); @@ -596,40 +583,24 @@ describe("Paragraph", () => { describe("#setNumbering", () => { it("should add list paragraph style to JSON", () => { - const numbering = new Numbering(); - const numberedAbstract = numbering.createAbstractNumbering(); - numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start"); - const letterNumbering = numbering.createConcreteNumbering(numberedAbstract); - const paragraph = new Paragraph({ numbering: { - num: letterNumbering, + reference: "test id", level: 0, }, }); const tree = new Formatter().format(paragraph); - expect(tree) - .to.have.property("w:p") - .which.is.an("array") - .which.has.length.at.least(1); - expect(tree["w:p"][0]) - .to.have.property("w:pPr") - .which.is.an("array") - .which.has.length.at.least(1); + expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1); + expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1); expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({ "w:pStyle": { _attr: { "w:val": "ListParagraph" } }, }); }); it("it should add numbered properties", () => { - const numbering = new Numbering(); - const numberedAbstract = numbering.createAbstractNumbering(); - numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start"); - const letterNumbering = numbering.createConcreteNumbering(numberedAbstract); - const paragraph = new Paragraph({ numbering: { - num: letterNumbering, + reference: "test id", level: 0, }, }); @@ -640,10 +611,7 @@ describe("Paragraph", () => { "w:pPr": [ { "w:pStyle": { _attr: { "w:val": "ListParagraph" } } }, { - "w:numPr": [ - { "w:ilvl": { _attr: { "w:val": 0 } } }, - { "w:numId": { _attr: { "w:val": letterNumbering.id } } }, - ], + "w:numPr": [{ "w:ilvl": { _attr: { "w:val": 0 } } }, { "w:numId": { _attr: { "w:val": "{test id}" } } }], }, ], }, @@ -652,6 +620,49 @@ describe("Paragraph", () => { }); }); + it("it should add bookmark", () => { + stub(shortid, "generate").callsFake(() => { + return "test-unique-id"; + }); + const paragraph = new Paragraph({ + children: [new Bookmark("test-id", "test")], + }); + const tree = new Formatter().format(paragraph); + expect(tree).to.deep.equal({ + "w:p": [ + { + "w:bookmarkStart": { + _attr: { + "w:id": "test-unique-id", + "w:name": "test-id", + }, + }, + }, + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "test", + ], + }, + ], + }, + { + "w:bookmarkEnd": { + _attr: { + "w:id": "test-unique-id", + }, + }, + }, + ], + }); + }); + describe("#style", () => { it("should set the paragraph style to the given styleId", () => { const paragraph = new Paragraph({ @@ -751,4 +762,82 @@ describe("Paragraph", () => { }); }); }); + + describe("#shading", () => { + it("should set shading to the given value", () => { + const paragraph = new Paragraph({ + shading: { + type: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "00FFFF", + fill: "FF0000", + }, + }); + const tree = new Formatter().format(paragraph); + expect(tree).to.deep.equal({ + "w:p": [ + { + "w:pPr": [ + { + "w:shd": { + _attr: { + "w:color": "00FFFF", + "w:fill": "FF0000", + "w:val": "reverseDiagStripe", + }, + }, + }, + ], + }, + ], + }); + }); + }); + + describe("#prepForXml", () => { + it("should set Internal Hyperlink", () => { + const paragraph = new Paragraph({ + children: [ + new ExternalHyperlink({ + child: new TextRun("test"), + link: "http://www.google.com", + }), + ], + }); + const fileMock = ({ + Relationships: { + createRelationship: () => ({}), + }, + } as unknown) as IViewWrapper; + paragraph.prepForXml(fileMock); + const tree = new Formatter().format(paragraph); + expect(tree).to.deep.equal({ + "w:p": [ + { + "w:hyperlink": [ + { + _attr: { + "r:id": "rIdtest-unique-id", + "w:history": 1, + }, + }, + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "test", + ], + }, + ], + }, + ], + }, + ], + }); + }); + }); }); diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index b11393ee37..7c05ee711c 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -1,51 +1,35 @@ // http://officeopenxml.com/WPparagraph.php -import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run"; -import { Num } from "file/numbering/num"; -import { XmlComponent } from "file/xml-components"; +import * as shortid from "shortid"; -import { Alignment, AlignmentType } from "./formatting/alignment"; -import { Bidirectional } from "./formatting/bidirectional"; -import { IBorderOptions, ThematicBreak } from "./formatting/border"; -import { IIndentAttributesProperties, Indent } from "./formatting/indent"; -import { KeepLines, KeepNext } from "./formatting/keep"; -import { PageBreak, PageBreakBefore } from "./formatting/page-break"; -import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing"; -import { HeadingLevel, Style } from "./formatting/style"; -import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop"; -import { NumberProperties } from "./formatting/unordered-list"; -import { Bookmark, Hyperlink, OutlineLevel } from "./links"; -import { ParagraphProperties } from "./properties"; +import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run"; +import { IXmlableObject, XmlComponent } from "file/xml-components"; + +import { IViewWrapper } from "../document-wrapper"; +import { TargetModeType } from "../relationships/relationship/relationship"; +import { DeletedTextRun, InsertedTextRun } from "../track-revision"; +import { PageBreak } from "./formatting/page-break"; +import { Bookmark, ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./links"; +import { Math } from "./math"; +import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties"; import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run"; -export interface IParagraphOptions { +export type ParagraphChild = + | TextRun + | PictureRun + | SymbolRun + | Bookmark + | PageBreak + | SequentialIdentifier + | FootnoteReferenceRun + | InternalHyperlink + | ExternalHyperlink + | InsertedTextRun + | DeletedTextRun + | Math; + +export interface IParagraphOptions extends IParagraphPropertiesOptions { readonly text?: string; - readonly border?: IBorderOptions; - readonly spacing?: ISpacingProperties; - readonly outlineLevel?: number; - readonly alignment?: AlignmentType; - readonly heading?: HeadingLevel; - readonly bidirectional?: boolean; - readonly thematicBreak?: boolean; - readonly pageBreakBefore?: boolean; - readonly contextualSpacing?: boolean; - readonly indent?: IIndentAttributesProperties; - readonly keepLines?: boolean; - readonly keepNext?: boolean; - readonly tabStops?: Array<{ - readonly position: number | TabStopPosition; - readonly type: TabStopType; - readonly leader?: LeaderType; - }>; - readonly style?: string; - readonly bullet?: { - readonly level: number; - }; - readonly numbering?: { - readonly num: Num; - readonly level: number; - readonly custom?: boolean; - }; - readonly children?: Array; + readonly children?: ParagraphChild[]; } export class Paragraph extends XmlComponent { @@ -68,9 +52,7 @@ export class Paragraph extends XmlComponent { return; } - this.properties = new ParagraphProperties({ - border: options.border, - }); + this.properties = new ParagraphProperties(options); this.root.push(this.properties); @@ -78,72 +60,6 @@ export class Paragraph extends XmlComponent { this.root.push(new TextRun(options.text)); } - if (options.spacing) { - this.properties.push(new Spacing(options.spacing)); - } - - if (options.outlineLevel !== undefined) { - this.properties.push(new OutlineLevel(options.outlineLevel)); - } - - if (options.alignment) { - this.properties.push(new Alignment(options.alignment)); - } - - if (options.heading) { - this.properties.push(new Style(options.heading)); - } - - if (options.bidirectional) { - this.properties.push(new Bidirectional()); - } - - if (options.thematicBreak) { - this.properties.push(new ThematicBreak()); - } - - if (options.pageBreakBefore) { - this.properties.push(new PageBreakBefore()); - } - - if (options.contextualSpacing) { - this.properties.push(new ContextualSpacing(options.contextualSpacing)); - } - - if (options.indent) { - this.properties.push(new Indent(options.indent)); - } - - if (options.keepLines) { - this.properties.push(new KeepLines()); - } - - if (options.keepNext) { - this.properties.push(new KeepNext()); - } - - if (options.tabStops) { - for (const tabStop of options.tabStops) { - this.properties.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader)); - } - } - - if (options.style) { - this.properties.push(new Style(options.style)); - } - - if (options.bullet) { - this.properties.push(new Style("ListParagraph")); - this.properties.push(new NumberProperties(1, options.bullet.level)); - } - - if (options.numbering) { - if (!options.numbering.custom) { - this.properties.push(new Style("ListParagraph")); - } - this.properties.push(new NumberProperties(options.numbering.num.id, options.numbering.level)); - } - if (options.children) { for (const child of options.children) { if (child instanceof Bookmark) { @@ -158,9 +74,22 @@ export class Paragraph extends XmlComponent { } } - public referenceFootnote(id: number): Paragraph { - this.root.push(new FootnoteReferenceRun(id)); - return this; + public prepForXml(file: IViewWrapper): IXmlableObject | undefined { + for (const element of this.root) { + if (element instanceof ExternalHyperlink) { + const index = this.root.indexOf(element); + const concreteHyperlink = new ConcreteHyperlink(element.options.child, shortid.generate().toLowerCase()); + file.Relationships.createRelationship( + concreteHyperlink.linkId, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", + element.options.link, + TargetModeType.EXTERNAL, + ); + this.root[index] = concreteHyperlink; + } + } + + return super.prepForXml(); } public addRunToFront(run: Run): Paragraph { diff --git a/src/file/paragraph/properties.ts b/src/file/paragraph/properties.ts index 35836ce30e..b12bfedd8e 100644 --- a/src/file/paragraph/properties.ts +++ b/src/file/paragraph/properties.ts @@ -1,19 +1,147 @@ // http://officeopenxml.com/WPparagraphProperties.php import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components"; +import { ShadingType } from "../table/shading"; +import { Alignment, AlignmentType } from "./formatting/alignment"; +import { Bidirectional } from "./formatting/bidirectional"; +import { Border, IBorderOptions, ThematicBreak } from "./formatting/border"; +import { IIndentAttributesProperties, Indent } from "./formatting/indent"; +import { KeepLines, KeepNext } from "./formatting/keep"; +import { PageBreakBefore } from "./formatting/page-break"; +import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing"; +import { HeadingLevel, Style } from "./formatting/style"; +import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop"; +import { NumberProperties } from "./formatting/unordered-list"; +import { OutlineLevel } from "./links"; +import { Shading } from "./run/formatting"; -import { Border, IBorderOptions } from "./formatting/border"; +export interface IParagraphStylePropertiesOptions { + readonly alignment?: AlignmentType; + readonly thematicBreak?: boolean; + readonly contextualSpacing?: boolean; + readonly rightTabStop?: number; + readonly leftTabStop?: number; + readonly indent?: IIndentAttributesProperties; + readonly spacing?: ISpacingProperties; + readonly keepNext?: boolean; + readonly keepLines?: boolean; + readonly outlineLevel?: number; +} -interface IParagraphPropertiesOptions { +export interface IParagraphPropertiesOptions extends IParagraphStylePropertiesOptions { readonly border?: IBorderOptions; + readonly heading?: HeadingLevel; + readonly bidirectional?: boolean; + readonly pageBreakBefore?: boolean; + readonly tabStops?: { + readonly position: number | TabStopPosition; + readonly type: TabStopType; + readonly leader?: LeaderType; + }[]; + readonly style?: string; + readonly bullet?: { + readonly level: number; + }; + readonly numbering?: { + readonly reference: string; + readonly level: number; + readonly custom?: boolean; + }; + readonly shading?: { + readonly type: ShadingType; + readonly fill: string; + readonly color: string; + }; } export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { - constructor(options: IParagraphPropertiesOptions) { + constructor(options?: IParagraphPropertiesOptions) { super("w:pPr"); + if (!options) { + return; + } + if (options.border) { this.push(new Border(options.border)); } + + if (options.spacing) { + this.push(new Spacing(options.spacing)); + } + + if (options.outlineLevel !== undefined) { + this.push(new OutlineLevel(options.outlineLevel)); + } + + if (options.alignment) { + this.push(new Alignment(options.alignment)); + } + + if (options.heading) { + this.push(new Style(options.heading)); + } + + if (options.bidirectional) { + this.push(new Bidirectional()); + } + + if (options.thematicBreak) { + this.push(new ThematicBreak()); + } + + if (options.pageBreakBefore) { + this.push(new PageBreakBefore()); + } + + if (options.contextualSpacing) { + this.push(new ContextualSpacing(options.contextualSpacing)); + } + + if (options.indent) { + this.push(new Indent(options.indent)); + } + + if (options.keepLines) { + this.push(new KeepLines()); + } + + if (options.keepNext) { + this.push(new KeepNext()); + } + + if (options.tabStops) { + for (const tabStop of options.tabStops) { + this.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader)); + } + } + + if (options.style) { + this.push(new Style(options.style)); + } + + if (options.bullet) { + this.push(new Style("ListParagraph")); + this.push(new NumberProperties(1, options.bullet.level)); + } + + if (options.numbering) { + if (!options.numbering.custom) { + this.push(new Style("ListParagraph")); + } + this.push(new NumberProperties(options.numbering.reference, options.numbering.level)); + } + + if (options.rightTabStop) { + this.push(new TabStop(TabStopType.RIGHT, options.rightTabStop)); + } + + if (options.leftTabStop) { + this.push(new TabStop(TabStopType.LEFT, options.leftTabStop)); + } + + if (options.shading) { + this.push(new Shading(options.shading.type, options.shading.fill, options.shading.color)); + } } public push(item: XmlComponent): void { diff --git a/src/file/paragraph/run/caps.ts b/src/file/paragraph/run/caps.ts deleted file mode 100644 index 0b9fb510be..0000000000 --- a/src/file/paragraph/run/caps.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { XmlComponent } from "file/xml-components"; - -export class SmallCaps extends XmlComponent { - constructor() { - super("w:smallCaps"); - } -} - -export class Caps extends XmlComponent { - constructor() { - super("w:caps"); - } -} diff --git a/src/file/paragraph/run/emphasis-mark.spec.ts b/src/file/paragraph/run/emphasis-mark.spec.ts new file mode 100644 index 0000000000..4ad4878f64 --- /dev/null +++ b/src/file/paragraph/run/emphasis-mark.spec.ts @@ -0,0 +1,29 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import * as em from "./emphasis-mark"; + +describe("EmphasisMark", () => { + describe("#constructor()", () => { + it("should create a new EmphasisMark object with w:em as the rootKey", () => { + const emphasisMark = new em.EmphasisMark(); + const tree = new Formatter().format(emphasisMark); + expect(tree).to.deep.equal({ + "w:em": { _attr: { "w:val": "dot" } }, + }); + }); + }); +}); + +describe("DotEmphasisMark", () => { + describe("#constructor()", () => { + it("should put value in attribute", () => { + const emphasisMark = new em.DotEmphasisMark(); + const tree = new Formatter().format(emphasisMark); + expect(tree).to.deep.equal({ + "w:em": { _attr: { "w:val": "dot" } }, + }); + }); + }); +}); diff --git a/src/file/paragraph/run/emphasis-mark.ts b/src/file/paragraph/run/emphasis-mark.ts new file mode 100644 index 0000000000..b8af756072 --- /dev/null +++ b/src/file/paragraph/run/emphasis-mark.ts @@ -0,0 +1,28 @@ +import { Attributes, XmlComponent } from "file/xml-components"; + +export enum EmphasisMarkType { + DOT = "dot", +} + +export abstract class BaseEmphasisMark extends XmlComponent { + protected constructor(emphasisMarkType: EmphasisMarkType) { + super("w:em"); + this.root.push( + new Attributes({ + val: emphasisMarkType, + }), + ); + } +} + +export class EmphasisMark extends BaseEmphasisMark { + constructor(emphasisMarkType: EmphasisMarkType = EmphasisMarkType.DOT) { + super(emphasisMarkType); + } +} + +export class DotEmphasisMark extends BaseEmphasisMark { + constructor() { + super(EmphasisMarkType.DOT); + } +} diff --git a/src/file/paragraph/run/formatting.ts b/src/file/paragraph/run/formatting.ts index 549f2ae552..3ef041d7d9 100644 --- a/src/file/paragraph/run/formatting.ts +++ b/src/file/paragraph/run/formatting.ts @@ -1,7 +1,9 @@ import { Attributes, XmlComponent } from "file/xml-components"; + export { Underline } from "./underline"; +export { EmphasisMark } from "./emphasis-mark"; export { SubScript, SuperScript } from "./script"; -export { RunFonts } from "./run-fonts"; +export { RunFonts, IFontAttributesProperties } from "./run-fonts"; export class Bold extends XmlComponent { constructor() { @@ -113,17 +115,6 @@ export class Imprint extends XmlComponent { } } -/* export class Shadow extends XmlComponent { - constructor() { - super("w:shadow"); - this.root.push( - new Attributes({ - val: true, - }), - ); - } -} */ - export class SmallCaps extends XmlComponent { constructor() { super("w:smallCaps"); diff --git a/src/file/paragraph/run/index.ts b/src/file/paragraph/run/index.ts index 353e794c06..3bf62d66cf 100644 --- a/src/file/paragraph/run/index.ts +++ b/src/file/paragraph/run/index.ts @@ -1,7 +1,10 @@ export * from "./run"; +export * from "./properties"; export * from "./text-run"; export * from "./symbol-run"; export * from "./picture-run"; export * from "./run-fonts"; export * from "./sequential-identifier"; export * from "./underline"; +export * from "./emphasis-mark"; +export * from "./tab"; diff --git a/src/file/paragraph/run/picture-run.ts b/src/file/paragraph/run/picture-run.ts index c796beebfc..e98dba573a 100644 --- a/src/file/paragraph/run/picture-run.ts +++ b/src/file/paragraph/run/picture-run.ts @@ -7,10 +7,6 @@ export class PictureRun extends Run { constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { super({}); - if (imageData === undefined) { - throw new Error("imageData cannot be undefined"); - } - const drawing = new Drawing(imageData, drawingOptions); this.root.push(drawing); diff --git a/src/file/paragraph/run/properties.ts b/src/file/paragraph/run/properties.ts index 903282b5a6..0bd082afc5 100644 --- a/src/file/paragraph/run/properties.ts +++ b/src/file/paragraph/run/properties.ts @@ -1,8 +1,183 @@ +import { ShadingType } from "file/table"; import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components"; +import { EmphasisMark, EmphasisMarkType } from "./emphasis-mark"; +import { + Bold, + BoldComplexScript, + Caps, + CharacterSpacing, + Color, + DoubleStrike, + Highlight, + HighlightComplexScript, + Italics, + ItalicsComplexScript, + RightToLeft, + Shading, + ShadowComplexScript, + Size, + SizeComplexScript, + SmallCaps, + Strike, +} from "./formatting"; +import { IFontAttributesProperties, RunFonts } from "./run-fonts"; +import { SubScript, SuperScript } from "./script"; +import { Style } from "./style"; +import { Underline, UnderlineType } from "./underline"; + +interface IFontOptions { + readonly name: string; + readonly hint?: string; +} + +export interface IRunStylePropertiesOptions { + readonly bold?: boolean; + readonly boldComplexScript?: boolean; + readonly italics?: boolean; + readonly italicsComplexScript?: boolean; + readonly underline?: { + readonly color?: string; + readonly type?: UnderlineType; + }; + readonly emphasisMark?: { + readonly type?: EmphasisMarkType; + }; + readonly color?: string; + readonly size?: number; + readonly sizeComplexScript?: boolean | number; + readonly rightToLeft?: boolean; + readonly smallCaps?: boolean; + readonly allCaps?: boolean; + readonly strike?: boolean; + readonly doubleStrike?: boolean; + readonly subScript?: boolean; + readonly superScript?: boolean; + readonly font?: string | IFontOptions | IFontAttributesProperties; + readonly highlight?: string; + readonly highlightComplexScript?: boolean | string; + readonly characterSpacing?: number; + readonly shading?: { + readonly type: ShadingType; + readonly fill: string; + readonly color: string; + }; + readonly shadingComplexScript?: boolean | IRunStylePropertiesOptions["shading"]; + readonly shadow?: IRunStylePropertiesOptions["shading"]; +} + +export interface IRunPropertiesOptions extends IRunStylePropertiesOptions { + readonly style?: string; +} export class RunProperties extends IgnoreIfEmptyXmlComponent { - constructor() { + constructor(options?: IRunPropertiesOptions) { super("w:rPr"); + + if (!options) { + return; + } + + if (options.bold) { + this.push(new Bold()); + } + if ((options.boldComplexScript === undefined && options.bold) || options.boldComplexScript) { + this.push(new BoldComplexScript()); + } + + if (options.italics) { + this.push(new Italics()); + } + if ((options.italicsComplexScript === undefined && options.italics) || options.italicsComplexScript) { + this.push(new ItalicsComplexScript()); + } + + if (options.underline) { + this.push(new Underline(options.underline.type, options.underline.color)); + } + + if (options.emphasisMark) { + this.push(new EmphasisMark(options.emphasisMark.type)); + } + + if (options.color) { + this.push(new Color(options.color)); + } + + if (options.size) { + this.push(new Size(options.size)); + } + const szCs = + options.sizeComplexScript === undefined || options.sizeComplexScript === true ? options.size : options.sizeComplexScript; + if (szCs) { + this.push(new SizeComplexScript(szCs)); + } + + if (options.rightToLeft) { + this.push(new RightToLeft()); + } + + if (options.smallCaps) { + this.push(new SmallCaps()); + } + + if (options.allCaps) { + this.push(new Caps()); + } + + if (options.strike) { + this.push(new Strike()); + } + + if (options.doubleStrike) { + this.push(new DoubleStrike()); + } + + if (options.subScript) { + this.push(new SubScript()); + } + + if (options.superScript) { + this.push(new SuperScript()); + } + + if (options.style) { + this.push(new Style(options.style)); + } + + if (options.font) { + if (typeof options.font === "string") { + this.push(new RunFonts(options.font)); + } else if ("name" in options.font) { + this.push(new RunFonts(options.font.name, options.font.hint)); + } else { + this.push(new RunFonts(options.font)); + } + } + + if (options.highlight) { + this.push(new Highlight(options.highlight)); + } + const highlightCs = + options.highlightComplexScript === undefined || options.highlightComplexScript === true + ? options.highlight + : options.highlightComplexScript; + if (highlightCs) { + this.push(new HighlightComplexScript(highlightCs)); + } + + if (options.characterSpacing) { + this.push(new CharacterSpacing(options.characterSpacing)); + } + + const shading = options.shading || options.shadow; + if (shading) { + this.push(new Shading(shading.type, shading.fill, shading.color)); + } + const shdCs = + options.shadingComplexScript === undefined || options.shadingComplexScript === true ? shading : options.shadingComplexScript; + if (shdCs) { + this.push(new ShadowComplexScript(shdCs.type, shdCs.fill, shdCs.color)); + } } public push(item: XmlComponent): void { diff --git a/src/file/paragraph/run/run-components/text.spec.ts b/src/file/paragraph/run/run-components/text.spec.ts index 57a3a5ede1..6393cebd8b 100644 --- a/src/file/paragraph/run/run-components/text.spec.ts +++ b/src/file/paragraph/run/run-components/text.spec.ts @@ -6,12 +6,6 @@ import { Text } from "./text"; describe("Text", () => { describe("#constructor", () => { - it("creates an empty text run if no text is given", () => { - const t = new Text(""); - const f = new Formatter().format(t); - expect(f).to.deep.equal({ "w:t": { _attr: { "xml:space": "preserve" } } }); - }); - it("adds the passed in text to the component", () => { const t = new Text(" this is\n text"); const f = new Formatter().format(t); diff --git a/src/file/paragraph/run/run-components/text.ts b/src/file/paragraph/run/run-components/text.ts index 5cac4500b4..f730d37d3b 100644 --- a/src/file/paragraph/run/run-components/text.ts +++ b/src/file/paragraph/run/run-components/text.ts @@ -9,8 +9,7 @@ export class Text extends XmlComponent { constructor(text: string) { super("w:t"); this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); - if (text) { - this.root.push(text); - } + + this.root.push(text); } } diff --git a/src/file/paragraph/run/run-fonts.spec.ts b/src/file/paragraph/run/run-fonts.spec.ts index 1eacc8ecc9..a0180eae81 100644 --- a/src/file/paragraph/run/run-fonts.spec.ts +++ b/src/file/paragraph/run/run-fonts.spec.ts @@ -21,5 +21,12 @@ describe("RunFonts", () => { }, }); }); + + it("uses the font attrs for ascii and eastAsia", () => { + const tree = new Formatter().format(new RunFonts({ ascii: "Times", eastAsia: "KaiTi" })); + expect(tree).to.deep.equal({ + "w:rFonts": { _attr: { "w:ascii": "Times", "w:eastAsia": "KaiTi" } }, + }); + }); }); }); diff --git a/src/file/paragraph/run/run-fonts.ts b/src/file/paragraph/run/run-fonts.ts index 10a441626c..c1eed32613 100644 --- a/src/file/paragraph/run/run-fonts.ts +++ b/src/file/paragraph/run/run-fonts.ts @@ -1,14 +1,14 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -interface IRunFontAttributesProperties { - readonly ascii: string; - readonly cs: string; - readonly eastAsia: string; - readonly hAnsi: string; +export interface IFontAttributesProperties { + readonly ascii?: string; + readonly cs?: string; + readonly eastAsia?: string; + readonly hAnsi?: string; readonly hint?: string; } -class RunFontAttributes extends XmlAttributeComponent { +class RunFontAttributes extends XmlAttributeComponent { protected readonly xmlKeys = { ascii: "w:ascii", cs: "w:cs", @@ -19,16 +19,26 @@ class RunFontAttributes extends XmlAttributeComponent { @@ -82,6 +85,30 @@ describe("Run", () => { }); }); + describe("#emphasisMark()", () => { + it("should default to 'dot'", () => { + const run = new Run({ + emphasisMark: {}, + }); + const tree = new Formatter().format(run); + expect(tree).to.deep.equal({ + "w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }], + }); + }); + + it("should set the style type if given", () => { + const run = new Run({ + emphasisMark: { + type: EmphasisMarkType.DOT, + }, + }); + const tree = new Formatter().format(run); + expect(tree).to.deep.equal({ + "w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }], + }); + }); + }); + describe("#smallCaps()", () => { it("it should add smallCaps to the properties", () => { const run = new Run({ @@ -89,7 +116,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:smallCaps": {} }] }], + "w:r": [{ "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }] }], }); }); }); @@ -101,7 +128,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:caps": {} }] }], + "w:r": [{ "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }] }], }); }); }); @@ -130,6 +157,30 @@ describe("Run", () => { }); }); + describe("#subScript()", () => { + it("it should add subScript to the properties", () => { + const run = new Run({ + subScript: true, + }); + const tree = new Formatter().format(run); + expect(tree).to.deep.equal({ + "w:r": [{ "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "subscript" } } }] }], + }); + }); + }); + + describe("#superScript()", () => { + it("it should add superScript to the properties", () => { + const run = new Run({ + superScript: true, + }); + const tree = new Formatter().format(run); + expect(tree).to.deep.equal({ + "w:r": [{ "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "superscript" } } }] }], + }); + }); + }); + describe("#highlight()", () => { it("it should add highlight to the properties", () => { const run = new Run({ @@ -188,22 +239,27 @@ describe("Run", () => { describe("#break()", () => { it("it should add break to the run", () => { - const run = new Run({}); - run.break(); + const run = new Run({ + break: 1, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:br": {} }], }); }); - }); - describe("#tab()", () => { - it("it should add break to the run", () => { - const run = new Run({}); - run.tab(); + it("it should add two breaks to the run", () => { + const run = new Run({ + break: 2, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:tab": {} }], + "w:r": [ + { "w:br": {} }, + { + "w:br": {}, + }, + ], }); }); }); @@ -220,7 +276,42 @@ describe("Run", () => { "w:r": [ { "w:rPr": [ - { "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } }, + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:cs": "Times", + "w:eastAsia": "Times", + "w:hAnsi": "Times", + }, + }, + }, + ], + }, + ], + }); + }); + + it("should set the font for ascii and eastAsia", () => { + const run = new Run({ + font: { + ascii: "Times", + eastAsia: "KaiTi", + }, + }); + const tree = new Formatter().format(run); + expect(tree).to.deep.equal({ + "w:r": [ + { + "w:rPr": [ + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:eastAsia": "KaiTi", + }, + }, + }, ], }, ], @@ -270,8 +361,10 @@ describe("Run", () => { describe("#numberOfTotalPages", () => { it("should set the run to the RTL mode", () => { - const run = new Run({}); - run.numberOfTotalPages(); + const run = new Run({ + children: [PageNumber.TOTAL_PAGES], + }); + const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [ @@ -286,8 +379,10 @@ describe("Run", () => { describe("#numberOfTotalPagesSection", () => { it("should set the run to the RTL mode", () => { - const run = new Run({}); - run.numberOfTotalPagesSection(); + const run = new Run({ + children: [PageNumber.TOTAL_PAGES_IN_SECTION], + }); + const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [ @@ -302,8 +397,9 @@ describe("Run", () => { describe("#pageNumber", () => { it("should set the run to the RTL mode", () => { - const run = new Run({}); - run.pageNumber(); + const run = new Run({ + children: [PageNumber.CURRENT], + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [ diff --git a/src/file/paragraph/run/run.ts b/src/file/paragraph/run/run.ts index e586f8807d..461fd9da29 100644 --- a/src/file/paragraph/run/run.ts +++ b/src/file/paragraph/run/run.ts @@ -1,63 +1,24 @@ // http://officeopenxml.com/WPtext.php -import { ShadingType } from "file/table"; import { XmlComponent } from "file/xml-components"; +import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run"; import { FieldInstruction } from "file/table-of-contents/field-instruction"; import { Break } from "./break"; -import { Caps, SmallCaps } from "./caps"; import { Begin, End, Separate } from "./field"; -import { - Bold, - BoldComplexScript, - Color, - DoubleStrike, - Highlight, - HighlightComplexScript, - Italics, - ItalicsComplexScript, - RightToLeft, - Shading, - ShadowComplexScript, - Size, - SizeComplexScript, - Strike, -} from "./formatting"; import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number"; -import { RunProperties } from "./properties"; -import { RunFonts } from "./run-fonts"; -import { SubScript, SuperScript } from "./script"; -import { Style } from "./style"; -import { Tab } from "./tab"; -import { Underline, UnderlineType } from "./underline"; +import { IRunPropertiesOptions, RunProperties } from "./properties"; +import { Text } from "./run-components/text"; -export interface IRunOptions { - readonly bold?: true; - readonly italics?: true; - readonly underline?: { - readonly color?: string; - readonly type?: UnderlineType; - }; - readonly color?: string; - readonly size?: number; - readonly rightToLeft?: boolean; - readonly smallCaps?: boolean; - readonly allCaps?: boolean; - readonly strike?: boolean; - readonly doubleStrike?: boolean; - readonly subScript?: boolean; - readonly superScript?: boolean; - readonly style?: string; - readonly font?: { - readonly name: string; - readonly hint?: string; - }; - readonly highlight?: string; - readonly shading?: { - readonly type: ShadingType; - readonly fill: string; - readonly color: string; - }; - readonly children?: Array; +export interface IRunOptions extends IRunPropertiesOptions { + readonly children?: (Begin | FieldInstruction | Separate | End | PageNumber | FootnoteReferenceRun | string)[]; + readonly break?: number; + readonly text?: string; +} + +export enum PageNumber { + CURRENT = "CURRENT", + TOTAL_PAGES = "TOTAL_PAGES", + TOTAL_PAGES_IN_SECTION = "TOTAL_PAGES_IN_SECTION", } export class Run extends XmlComponent { @@ -65,116 +26,48 @@ export class Run extends XmlComponent { constructor(options: IRunOptions) { super("w:r"); - this.properties = new RunProperties(); + this.properties = new RunProperties(options); this.root.push(this.properties); - if (options.bold) { - this.properties.push(new Bold()); - this.properties.push(new BoldComplexScript()); - } - - if (options.italics) { - this.properties.push(new Italics()); - this.properties.push(new ItalicsComplexScript()); - } - - if (options.underline) { - this.properties.push(new Underline(options.underline.type, options.underline.color)); - } - - if (options.color) { - this.properties.push(new Color(options.color)); - } - - if (options.size) { - this.properties.push(new Size(options.size)); - this.properties.push(new SizeComplexScript(options.size)); - } - - if (options.rightToLeft) { - this.properties.push(new RightToLeft()); - } - - if (options.smallCaps) { - this.properties.push(new SmallCaps()); - } - - if (options.allCaps) { - this.properties.push(new Caps()); - } - - if (options.strike) { - this.properties.push(new Strike()); - } - - if (options.doubleStrike) { - this.properties.push(new DoubleStrike()); - } - - if (options.subScript) { - this.properties.push(new SubScript()); - } - - if (options.superScript) { - this.properties.push(new SuperScript()); - } - - if (options.style) { - this.properties.push(new Style(options.style)); - } - - if (options.font) { - this.properties.push(new RunFonts(options.font.name, options.font.hint)); - } - - if (options.highlight) { - this.properties.push(new Highlight(options.highlight)); - this.properties.push(new HighlightComplexScript(options.highlight)); - } - - if (options.shading) { - this.properties.push(new Shading(options.shading.type, options.shading.fill, options.shading.color)); - this.properties.push(new ShadowComplexScript(options.shading.type, options.shading.fill, options.shading.color)); - } - if (options.children) { for (const child of options.children) { + if (typeof child === "string") { + switch (child) { + case PageNumber.CURRENT: + this.root.push(new Begin()); + this.root.push(new Page()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + case PageNumber.TOTAL_PAGES: + this.root.push(new Begin()); + this.root.push(new NumberOfPages()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + case PageNumber.TOTAL_PAGES_IN_SECTION: + this.root.push(new Begin()); + this.root.push(new NumberOfPagesSection()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + default: + this.root.push(new Text(child)); + break; + } + continue; + } + this.root.push(child); } + } else if (options.text) { + this.root.push(new Text(options.text)); + } + + if (options.break) { + for (let i = 0; i < options.break; i++) { + this.root.splice(1, 0, new Break()); + } } } - - public break(): Run { - this.root.splice(1, 0, new Break()); - return this; - } - - public tab(): Run { - this.root.splice(1, 0, new Tab()); - return this; - } - - public pageNumber(): Run { - this.root.push(new Begin()); - this.root.push(new Page()); - this.root.push(new Separate()); - this.root.push(new End()); - return this; - } - - public numberOfTotalPages(): Run { - this.root.push(new Begin()); - this.root.push(new NumberOfPages()); - this.root.push(new Separate()); - this.root.push(new End()); - return this; - } - - public numberOfTotalPagesSection(): Run { - this.root.push(new Begin()); - this.root.push(new NumberOfPagesSection()); - this.root.push(new Separate()); - this.root.push(new End()); - return this; - } } diff --git a/src/file/paragraph/run/symbol-run.spec.ts b/src/file/paragraph/run/symbol-run.spec.ts index f3faee8bb0..c41e6e1d51 100644 --- a/src/file/paragraph/run/symbol-run.spec.ts +++ b/src/file/paragraph/run/symbol-run.spec.ts @@ -1,5 +1,7 @@ import { expect } from "chai"; +import { EmphasisMarkType } from "./emphasis-mark"; + import { Formatter } from "export/formatter"; import { UnderlineType } from "./underline"; @@ -44,6 +46,9 @@ describe("SymbolRun", () => { color: "red", type: UnderlineType.DOUBLE, }, + emphasisMark: { + type: EmphasisMarkType.DOT, + }, color: "green", size: 40, highlight: "yellow", @@ -59,6 +64,7 @@ describe("SymbolRun", () => { { "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }, { "w:u": { _attr: { "w:val": "double", "w:color": "red" } } }, + { "w:em": { _attr: { "w:val": "dot" } } }, { "w:color": { _attr: { "w:val": "green" } } }, { "w:sz": { _attr: { "w:val": 40 } } }, { "w:szCs": { _attr: { "w:val": 40 } } }, diff --git a/src/file/paragraph/run/text-run.spec.ts b/src/file/paragraph/run/text-run.spec.ts index 077d6300f0..b36b3c3139 100644 --- a/src/file/paragraph/run/text-run.spec.ts +++ b/src/file/paragraph/run/text-run.spec.ts @@ -1,6 +1,7 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; +import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run"; import { TextRun } from "./text-run"; @@ -16,4 +17,25 @@ describe("TextRun", () => { }); }); }); + + describe("#referenceFootnote()", () => { + it("should add a valid footnote reference", () => { + run = new TextRun({ + children: ["test", new FootnoteReferenceRun(1)], + }); + const tree = new Formatter().format(run); + + expect(tree).to.deep.equal({ + "w:r": [ + { "w:t": [{ _attr: { "xml:space": "preserve" } }, "test"] }, + { + "w:r": [ + { "w:rPr": [{ "w:rStyle": { _attr: { "w:val": "FootnoteReference" } } }] }, + { "w:footnoteReference": { _attr: { "w:id": 1 } } }, + ], + }, + ], + }); + }); + }); }); diff --git a/src/file/paragraph/run/text-run.ts b/src/file/paragraph/run/text-run.ts index eeacf2dfd5..200651c9de 100644 --- a/src/file/paragraph/run/text-run.ts +++ b/src/file/paragraph/run/text-run.ts @@ -1,12 +1,8 @@ import { IRunOptions, Run } from "./run"; import { Text } from "./run-components/text"; -export interface ITextRunOptions extends IRunOptions { - readonly text: string; -} - export class TextRun extends Run { - constructor(options: ITextRunOptions | string) { + constructor(options: IRunOptions | string) { if (typeof options === "string") { super({}); this.root.push(new Text(options)); @@ -14,6 +10,5 @@ export class TextRun extends Run { } super(options); - this.root.push(new Text(options.text)); } } diff --git a/src/file/relationships/relationship/relationship.ts b/src/file/relationships/relationship/relationship.ts index 82672644c9..2b928de890 100644 --- a/src/file/relationships/relationship/relationship.ts +++ b/src/file/relationships/relationship/relationship.ts @@ -13,6 +13,7 @@ export type RelationshipType = | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" | "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties" | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"; diff --git a/src/file/relationships/relationships.ts b/src/file/relationships/relationships.ts index bd56ff1aab..3a5447c2d9 100644 --- a/src/file/relationships/relationships.ts +++ b/src/file/relationships/relationships.ts @@ -16,7 +16,7 @@ export class Relationships extends XmlComponent { this.root.push(relationship); } - public createRelationship(id: number, type: RelationshipType, target: string, targetMode?: TargetModeType): Relationship { + public createRelationship(id: number | string, type: RelationshipType, target: string, targetMode?: TargetModeType): Relationship { const relationship = new Relationship(`rId${id}`, type, target, targetMode); this.addRelationship(relationship); diff --git a/src/file/settings/compatibility-setting/compatibility-setting.spec.ts b/src/file/settings/compatibility-setting/compatibility-setting.spec.ts new file mode 100644 index 0000000000..0f65697cda --- /dev/null +++ b/src/file/settings/compatibility-setting/compatibility-setting.spec.ts @@ -0,0 +1,23 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; + +import { CompatibilitySetting } from "./compatibility-setting"; + +describe("CompatibilitySetting", () => { + describe("#constructor", () => { + it("creates an initially empty property object", () => { + const compatibilitySetting = new CompatibilitySetting(15); + + const tree = new Formatter().format(compatibilitySetting); + expect(tree).to.deep.equal({ + "w:compatSetting": { + _attr: { + "w:name": "compatibilityMode", + "w:uri": "http://schemas.microsoft.com/office/word", + "w:val": 15, + }, + }, + }); + }); + }); +}); diff --git a/src/file/settings/compatibility-setting/compatibility-setting.ts b/src/file/settings/compatibility-setting/compatibility-setting.ts new file mode 100644 index 0000000000..9f2a0b4982 --- /dev/null +++ b/src/file/settings/compatibility-setting/compatibility-setting.ts @@ -0,0 +1,27 @@ +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +export class CompatibilitySettingAttributes extends XmlAttributeComponent<{ + readonly version: number; + readonly name: string; + readonly uri: string; +}> { + protected readonly xmlKeys = { + version: "w:val", + name: "w:name", + uri: "w:uri", + }; +} + +export class CompatibilitySetting extends XmlComponent { + constructor(version: number) { + super("w:compatSetting"); + + this.root.push( + new CompatibilitySettingAttributes({ + version, + uri: "http://schemas.microsoft.com/office/word", + name: "compatibilityMode", + }), + ); + } +} diff --git a/src/file/settings/compatibility.spec.ts b/src/file/settings/compatibility.spec.ts index 6399dcfeea..fa9809672d 100644 --- a/src/file/settings/compatibility.spec.ts +++ b/src/file/settings/compatibility.spec.ts @@ -1,13 +1,14 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { Compatibility } from "file/settings/compatibility"; import { EMPTY_OBJECT } from "file/xml-components"; +import { Compatibility } from "./compatibility"; + describe("Compatibility", () => { describe("#constructor", () => { it("creates an initially empty property object", () => { - const compatibility = new Compatibility(); + const compatibility = new Compatibility({}); const tree = new Formatter().format(compatibility); expect(tree).to.deep.equal({ "w:compat": EMPTY_OBJECT }); @@ -16,8 +17,9 @@ describe("Compatibility", () => { describe("#doNotExpandShiftReturn", () => { it("should create a setting for not justifying lines ending in soft line break", () => { - const compatibility = new Compatibility(); - compatibility.doNotExpandShiftReturn(); + const compatibility = new Compatibility({ + doNotExpandShiftReturn: true, + }); const tree = new Formatter().format(compatibility); expect(tree).to.deep.equal({ "w:compat": [{ "w:doNotExpandShiftReturn": EMPTY_OBJECT }] }); diff --git a/src/file/settings/compatibility.ts b/src/file/settings/compatibility.ts index afd2dd0f37..fe63da92c5 100644 --- a/src/file/settings/compatibility.ts +++ b/src/file/settings/compatibility.ts @@ -1,4 +1,5 @@ import { XmlComponent } from "file/xml-components"; +import { CompatibilitySetting } from "./compatibility-setting/compatibility-setting"; class DoNotExpandShiftReturn extends XmlComponent { constructor() { @@ -6,14 +7,21 @@ class DoNotExpandShiftReturn extends XmlComponent { } } +export interface ICompatibilityOptions { + readonly doNotExpandShiftReturn?: boolean; + readonly version?: number; +} + export class Compatibility extends XmlComponent { - constructor() { + constructor(options: ICompatibilityOptions) { super("w:compat"); - } - public doNotExpandShiftReturn(): Compatibility { - this.root.push(new DoNotExpandShiftReturn()); + if (options.doNotExpandShiftReturn) { + this.root.push(new DoNotExpandShiftReturn()); + } - return this; + if (options.version) { + this.root.push(new CompatibilitySetting(options.version)); + } } } diff --git a/src/file/settings/display-background-shape.spec.ts b/src/file/settings/display-background-shape.spec.ts new file mode 100644 index 0000000000..34c23b65db --- /dev/null +++ b/src/file/settings/display-background-shape.spec.ts @@ -0,0 +1,17 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { DisplayBackgroundShape } from "./display-background-shape"; + +describe("DisplayBackgroundShape", () => { + describe("#constructor()", () => { + it("should create", () => { + const displayBackgroundShape = new DisplayBackgroundShape(); + const tree = new Formatter().format(displayBackgroundShape); + expect(tree).to.deep.equal({ + "w:displayBackgroundShape": {}, + }); + }); + }); +}); diff --git a/src/file/settings/display-background-shape.ts b/src/file/settings/display-background-shape.ts new file mode 100644 index 0000000000..bd0cd15675 --- /dev/null +++ b/src/file/settings/display-background-shape.ts @@ -0,0 +1,9 @@ +// http://officeopenxml.com/WPdocument.php +// http://www.datypic.com/sc/ooxml/e-w_background-1.html +import { XmlComponent } from "file/xml-components"; + +export class DisplayBackgroundShape extends XmlComponent { + constructor() { + super("w:displayBackgroundShape"); + } +} diff --git a/src/file/settings/settings.spec.ts b/src/file/settings/settings.spec.ts index 1e34c781c2..381b24d372 100644 --- a/src/file/settings/settings.spec.ts +++ b/src/file/settings/settings.spec.ts @@ -7,7 +7,7 @@ import { Settings } from "./settings"; describe("Settings", () => { describe("#constructor", () => { it("should create a empty Settings with correct rootKey", () => { - const settings = new Settings(); + const settings = new Settings({}); const tree = new Formatter().format(settings); let keys = Object.keys(tree); expect(keys).is.an.instanceof(Array); @@ -15,8 +15,7 @@ describe("Settings", () => { expect(keys[0]).to.be.equal("w:settings"); keys = Object.keys(tree["w:settings"]); expect(keys).is.an.instanceof(Array); - expect(keys).has.length(1); - expect(keys[0]).to.be.equal("_attr"); + expect(keys).has.length(3); }); }); describe("#addUpdateFields", () => { @@ -28,16 +27,16 @@ describe("Settings", () => { expect(keys[0]).to.be.equal("w:settings"); const rootArray = tree["w:settings"]; expect(rootArray).is.an.instanceof(Array); - expect(rootArray).has.length(2); + expect(rootArray).has.length(4); keys = Object.keys(rootArray[0]); expect(keys).is.an.instanceof(Array); expect(keys).has.length(1); expect(keys[0]).to.be.equal("_attr"); - keys = Object.keys(rootArray[1]); + keys = Object.keys(rootArray[3]); expect(keys).is.an.instanceof(Array); expect(keys).has.length(1); expect(keys[0]).to.be.equal("w:updateFields"); - const updateFields = rootArray[1]["w:updateFields"]; + const updateFields = rootArray[3]["w:updateFields"]; keys = Object.keys(updateFields); expect(keys).is.an.instanceof(Array); expect(keys).has.length(1); @@ -46,12 +45,12 @@ describe("Settings", () => { expect(updateFieldsAttr["w:val"]).to.be.equal(true); }; it("should add a UpdateFields with value true", () => { - const settings = new Settings(); + const settings = new Settings({}); settings.addUpdateFields(); assertSettingsWithUpdateFields(settings); }); it("should add a UpdateFields with value true only once", () => { - const settings = new Settings(); + const settings = new Settings({}); settings.addUpdateFields(); assertSettingsWithUpdateFields(settings); settings.addUpdateFields(); @@ -59,16 +58,15 @@ describe("Settings", () => { }); }); describe("#addCompatibility", () => { - it("should add an empty Compatibility", () => { - const settings = new Settings(); - settings.addCompatibility(); + it("should add an empty Compatibility by default", () => { + const settings = new Settings({}); const tree = new Formatter().format(settings); let keys: string[] = Object.keys(tree); expect(keys[0]).to.be.equal("w:settings"); const rootArray = tree["w:settings"]; expect(rootArray).is.an.instanceof(Array); - expect(rootArray).has.length(2); + expect(rootArray).has.length(3); keys = Object.keys(rootArray[0]); expect(keys).is.an.instanceof(Array); expect(keys).has.length(1); @@ -77,6 +75,58 @@ describe("Settings", () => { expect(keys).is.an.instanceof(Array); expect(keys).has.length(1); expect(keys[0]).to.be.equal("w:compat"); + expect(rootArray[1]["w:compat"][0]).to.deep.equal({ + "w:compatSetting": { + _attr: { + "w:val": 15, + "w:uri": "http://schemas.microsoft.com/office/word", + "w:name": "compatibilityMode", + }, + }, + }); + }); + }); + describe("#addTrackRevisions", () => { + it("should add an empty Track Revisions", () => { + const settings = new Settings({}); + settings.addTrackRevisions(); + + const tree = new Formatter().format(settings); + let keys: string[] = Object.keys(tree); + expect(keys[0]).to.be.equal("w:settings"); + const rootArray = tree["w:settings"]; + expect(rootArray).is.an.instanceof(Array); + expect(rootArray).has.length(4); + keys = Object.keys(rootArray[0]); + expect(keys).is.an.instanceof(Array); + expect(keys).has.length(1); + expect(keys[0]).to.be.equal("_attr"); + keys = Object.keys(rootArray[3]); + expect(keys).is.an.instanceof(Array); + expect(keys).has.length(1); + expect(keys[0]).to.be.equal("w:trackRevisions"); + }); + }); + describe("#addTrackRevisionsTwice", () => { + it("should add an empty Track Revisions if called twice", () => { + const settings = new Settings({}); + settings.addTrackRevisions(); + settings.addTrackRevisions(); + + const tree = new Formatter().format(settings); + let keys: string[] = Object.keys(tree); + expect(keys[0]).to.be.equal("w:settings"); + const rootArray = tree["w:settings"]; + expect(rootArray).is.an.instanceof(Array); + expect(rootArray).has.length(4); + keys = Object.keys(rootArray[0]); + expect(keys).is.an.instanceof(Array); + expect(keys).has.length(1); + expect(keys[0]).to.be.equal("_attr"); + keys = Object.keys(rootArray[3]); + expect(keys).is.an.instanceof(Array); + expect(keys).has.length(1); + expect(keys[0]).to.be.equal("w:trackRevisions"); }); }); }); diff --git a/src/file/settings/settings.ts b/src/file/settings/settings.ts index abae0e61d4..e63d539a39 100644 --- a/src/file/settings/settings.ts +++ b/src/file/settings/settings.ts @@ -1,5 +1,7 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { Compatibility } from "./compatibility"; +import { DisplayBackgroundShape } from "./display-background-shape"; +import { TrackRevisions } from "./track-revisions"; import { UpdateFields } from "./update-fields"; export interface ISettingsAttributesProperties { @@ -44,10 +46,15 @@ export class SettingsAttributes extends XmlAttributeComponent child instanceof Compatibility)) { - this.addChildElement(this.compatibility); + public addTrackRevisions(): TrackRevisions { + if (!this.root.find((child) => child instanceof TrackRevisions)) { + this.addChildElement(this.trackRevisions); } - return this.compatibility; + return this.trackRevisions; } } diff --git a/src/file/settings/track-revisions.spec.ts b/src/file/settings/track-revisions.spec.ts new file mode 100644 index 0000000000..3875d51f0a --- /dev/null +++ b/src/file/settings/track-revisions.spec.ts @@ -0,0 +1,16 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { TrackRevisions } from "file/settings/track-revisions"; + +import { EMPTY_OBJECT } from "file/xml-components"; + +describe("TrackRevisions", () => { + describe("#constructor", () => { + it("creates an initially empty property object", () => { + const trackRevisions = new TrackRevisions(); + + const tree = new Formatter().format(trackRevisions); + expect(tree).to.deep.equal({ "w:trackRevisions": EMPTY_OBJECT }); + }); + }); +}); diff --git a/src/file/settings/track-revisions.ts b/src/file/settings/track-revisions.ts new file mode 100644 index 0000000000..2da692827e --- /dev/null +++ b/src/file/settings/track-revisions.ts @@ -0,0 +1,7 @@ +import { XmlComponent } from "file/xml-components"; + +export class TrackRevisions extends XmlComponent { + constructor() { + super("w:trackRevisions"); + } +} diff --git a/src/file/styles/defaults/document-defaults.spec.ts b/src/file/styles/defaults/document-defaults.spec.ts new file mode 100644 index 0000000000..79ca9cccf7 --- /dev/null +++ b/src/file/styles/defaults/document-defaults.spec.ts @@ -0,0 +1,45 @@ +import { expect } from "chai"; + +import { DocumentDefaults } from "./document-defaults"; + +import { Formatter } from "export/formatter"; + +describe("DocumentDefaults", () => { + it("#constructor", () => { + const defaults = new DocumentDefaults({ + paragraph: { spacing: { line: 240 } }, + run: { color: "808080" }, + }); + const tree = new Formatter().format(defaults); + expect(tree).to.deep.equal({ + "w:docDefaults": [ + { + "w:rPrDefault": [ + { + "w:rPr": [ + { + "w:color": { _attr: { "w:val": "808080" } }, + }, + ], + }, + ], + }, + { + "w:pPrDefault": [ + { + "w:pPr": [ + { + "w:spacing": { + _attr: { + "w:line": 240, + }, + }, + }, + ], + }, + ], + }, + ], + }); + }); +}); diff --git a/src/file/styles/defaults/document-defaults.ts b/src/file/styles/defaults/document-defaults.ts new file mode 100644 index 0000000000..1f97bb2b07 --- /dev/null +++ b/src/file/styles/defaults/document-defaults.ts @@ -0,0 +1,25 @@ +import { IParagraphStylePropertiesOptions } from "file/paragraph/properties"; +import { IRunStylePropertiesOptions } from "file/paragraph/run/properties"; +import { XmlComponent } from "file/xml-components"; +import { ParagraphPropertiesDefaults } from "./paragraph-properties"; +import { RunPropertiesDefaults } from "./run-properties"; + +export interface IDocumentDefaultsOptions { + readonly paragraph?: IParagraphStylePropertiesOptions; + readonly run?: IRunStylePropertiesOptions; +} + +export class DocumentDefaults extends XmlComponent { + private readonly runPropertiesDefaults: RunPropertiesDefaults; + private readonly paragraphPropertiesDefaults: ParagraphPropertiesDefaults; + + constructor(options?: IDocumentDefaultsOptions) { + super("w:docDefaults"); + + this.runPropertiesDefaults = new RunPropertiesDefaults(options && options.run); + this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults(options && options.paragraph); + + this.root.push(this.runPropertiesDefaults); + this.root.push(this.paragraphPropertiesDefaults); + } +} diff --git a/src/file/styles/defaults/index.ts b/src/file/styles/defaults/index.ts index 2b6c49e299..986aa6194d 100644 --- a/src/file/styles/defaults/index.ts +++ b/src/file/styles/defaults/index.ts @@ -1,16 +1,3 @@ -import { XmlComponent } from "file/xml-components"; -import { ParagraphPropertiesDefaults } from "./paragraph-properties"; -import { RunPropertiesDefaults } from "./run-properties"; - -export class DocumentDefaults extends XmlComponent { - private readonly runPropertiesDefaults: RunPropertiesDefaults; - private readonly paragraphPropertiesDefaults: ParagraphPropertiesDefaults; - - constructor() { - super("w:docDefaults"); - this.runPropertiesDefaults = new RunPropertiesDefaults(); - this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults(); - this.root.push(this.runPropertiesDefaults); - this.root.push(this.paragraphPropertiesDefaults); - } -} +export * from "./paragraph-properties"; +export * from "./run-properties"; +export * from "./document-defaults"; diff --git a/src/file/styles/defaults/paragraph-properties.ts b/src/file/styles/defaults/paragraph-properties.ts index c5f2bee86c..cac92575a4 100644 --- a/src/file/styles/defaults/paragraph-properties.ts +++ b/src/file/styles/defaults/paragraph-properties.ts @@ -1,9 +1,9 @@ -import { ParagraphProperties } from "file/paragraph/properties"; +import { IParagraphStylePropertiesOptions, ParagraphProperties } from "file/paragraph/properties"; import { XmlComponent } from "file/xml-components"; export class ParagraphPropertiesDefaults extends XmlComponent { - constructor() { + constructor(options?: IParagraphStylePropertiesOptions) { super("w:pPrDefault"); - this.root.push(new ParagraphProperties({})); + this.root.push(new ParagraphProperties(options)); } } diff --git a/src/file/styles/defaults/run-properties.ts b/src/file/styles/defaults/run-properties.ts index 1ab8f5752c..f4e594ab99 100644 --- a/src/file/styles/defaults/run-properties.ts +++ b/src/file/styles/defaults/run-properties.ts @@ -1,25 +1,12 @@ -import { Size, SizeComplexScript } from "file/paragraph/run/formatting"; -import { RunProperties } from "file/paragraph/run/properties"; -import { RunFonts } from "file/paragraph/run/run-fonts"; +import { IRunStylePropertiesOptions, RunProperties } from "file/paragraph/run/properties"; import { XmlComponent } from "file/xml-components"; export class RunPropertiesDefaults extends XmlComponent { private readonly properties: RunProperties; - constructor() { + constructor(options?: IRunStylePropertiesOptions) { super("w:rPrDefault"); - this.properties = new RunProperties(); + this.properties = new RunProperties(options); this.root.push(this.properties); } - - public size(size: number): RunPropertiesDefaults { - this.properties.push(new Size(size)); - this.properties.push(new SizeComplexScript(size)); - return this; - } - - public font(fontName: string): RunPropertiesDefaults { - this.properties.push(new RunFonts(fontName)); - return this; - } } diff --git a/src/file/styles/factory.ts b/src/file/styles/factory.ts index f5bca8248d..097c812433 100644 --- a/src/file/styles/factory.ts +++ b/src/file/styles/factory.ts @@ -1,7 +1,7 @@ import { DocumentAttributes } from "../document/document-attributes"; import { IStylesOptions } from "./styles"; -import { DocumentDefaults } from "./defaults"; +import { DocumentDefaults, IDocumentDefaultsOptions } from "./defaults"; import { FootnoteReferenceStyle, FootnoteText, @@ -13,12 +13,32 @@ import { Heading5Style, Heading6Style, HyperlinkStyle, + IBaseCharacterStyleOptions, + IBaseParagraphStyleOptions, ListParagraph, + StrongStyle, TitleStyle, } from "./style"; +export interface IDefaultStylesOptions { + readonly document?: IDocumentDefaultsOptions; + readonly title?: IBaseParagraphStyleOptions; + readonly heading1?: IBaseParagraphStyleOptions; + readonly heading2?: IBaseParagraphStyleOptions; + readonly heading3?: IBaseParagraphStyleOptions; + readonly heading4?: IBaseParagraphStyleOptions; + readonly heading5?: IBaseParagraphStyleOptions; + readonly heading6?: IBaseParagraphStyleOptions; + readonly strong?: IBaseParagraphStyleOptions; + readonly listParagraph?: IBaseParagraphStyleOptions; + readonly hyperlink?: IBaseCharacterStyleOptions; + readonly footnoteReference?: IBaseCharacterStyleOptions; + readonly footnoteText?: IBaseParagraphStyleOptions; + readonly footnoteTextChar?: IBaseCharacterStyleOptions; +} + export class DefaultStylesFactory { - public newInstance(): IStylesOptions { + public newInstance(options: IDefaultStylesOptions = {}): IStylesOptions { const documentAttributes = new DocumentAttributes({ mc: "http://schemas.openxmlformats.org/markup-compatibility/2006", r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships", @@ -30,51 +50,64 @@ export class DefaultStylesFactory { return { initialStyles: documentAttributes, importedStyles: [ - new DocumentDefaults(), + new DocumentDefaults(options.document), new TitleStyle({ run: { size: 56, }, + ...options.title, }), new Heading1Style({ run: { color: "2E74B5", size: 32, }, + ...options.heading1, }), new Heading2Style({ run: { color: "2E74B5", size: 26, }, + ...options.heading2, }), new Heading3Style({ run: { color: "1F4D78", size: 24, }, + ...options.heading3, }), new Heading4Style({ run: { color: "2E74B5", italics: true, }, + ...options.heading4, }), new Heading5Style({ run: { color: "2E74B5", }, + ...options.heading5, }), new Heading6Style({ run: { color: "1F4D78", }, + ...options.heading6, }), - new ListParagraph({}), - new HyperlinkStyle({}), - new FootnoteReferenceStyle({}), - new FootnoteText({}), - new FootnoteTextChar({}), + new StrongStyle({ + run: { + bold: true, + }, + ...options.strong, + }), + new ListParagraph(options.listParagraph || {}), + new HyperlinkStyle(options.hyperlink || {}), + new FootnoteReferenceStyle(options.footnoteReference || {}), + new FootnoteText(options.footnoteText || {}), + new FootnoteTextChar(options.footnoteTextChar || {}), ], }; } diff --git a/src/file/styles/index.ts b/src/file/styles/index.ts index 144bbcb1fd..e18813fbb8 100644 --- a/src/file/styles/index.ts +++ b/src/file/styles/index.ts @@ -1,3 +1,4 @@ export * from "./styles"; export * from "./style/character-style"; export * from "./style/paragraph-style"; +export * from "./defaults"; diff --git a/src/file/styles/style/character-style.spec.ts b/src/file/styles/style/character-style.spec.ts index fe269bfceb..c7adf4ff97 100644 --- a/src/file/styles/style/character-style.spec.ts +++ b/src/file/styles/style/character-style.spec.ts @@ -1,16 +1,17 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; +import { EmphasisMarkType } from "file/paragraph/run/emphasis-mark"; import { UnderlineType } from "file/paragraph/run/underline"; import { ShadingType } from "file/table"; import { EMPTY_OBJECT } from "file/xml-components"; -import { CharacterStyle } from "./character-style"; +import { StyleForCharacter } from "./character-style"; describe("CharacterStyle", () => { describe("#constructor", () => { it("should set the style type to character and use the given style id", () => { - const style = new CharacterStyle({ id: "myStyleId" }); + const style = new StyleForCharacter({ id: "myStyleId" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -30,7 +31,7 @@ describe("CharacterStyle", () => { }); it("should set the name of the style, if given", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", name: "Style Name", }); @@ -54,7 +55,7 @@ describe("CharacterStyle", () => { }); it("should add smallCaps", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { smallCaps: true, @@ -82,7 +83,7 @@ describe("CharacterStyle", () => { }); it("should add allCaps", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { allCaps: true, @@ -110,7 +111,7 @@ describe("CharacterStyle", () => { }); it("should add strike", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { strike: true, @@ -138,7 +139,7 @@ describe("CharacterStyle", () => { }); it("should add double strike", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { doubleStrike: true, @@ -166,7 +167,7 @@ describe("CharacterStyle", () => { }); it("should add sub script", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { subScript: true, @@ -201,8 +202,8 @@ describe("CharacterStyle", () => { }); }); - it("should add font", () => { - const style = new CharacterStyle({ + it("should add font by name", () => { + const style = new StyleForCharacter({ id: "myStyleId", run: { font: "test font", @@ -240,8 +241,48 @@ describe("CharacterStyle", () => { }); }); + it("should add font for ascii and eastAsia", () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { + font: { + ascii: "test font ascii", + eastAsia: "test font eastAsia", + }, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": [ + { + "w:rFonts": { + _attr: { + "w:ascii": "test font ascii", + "w:eastAsia": "test font eastAsia", + }, + }, + }, + ], + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, + }, + }, + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); + }); + it("should add character spacing", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { characterSpacing: 100, @@ -271,7 +312,7 @@ describe("CharacterStyle", () => { describe("formatting methods: style attributes", () => { it("#basedOn", () => { - const style = new CharacterStyle({ id: "myStyleId", basedOn: "otherId" }); + const style = new StyleForCharacter({ id: "myStyleId", basedOn: "otherId" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -293,37 +334,58 @@ describe("CharacterStyle", () => { }); describe("formatting methods: run properties", () => { - it("#size", () => { - const style = new CharacterStyle({ - id: "myStyleId", - run: { - size: 24, - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], - }, - { - "w:uiPriority": { - _attr: { - "w:val": 99, + const sizeTests = [ + { + size: 24, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: true, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: false, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: 26, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }], + }, + ]; + sizeTests.forEach(({ size, sizeComplexScript, expected }) => { + it(`#size ${size} cs ${sizeComplexScript}`, () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { size, sizeComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": expected, + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, }, }, - }, - { - "w:unhideWhenUsed": EMPTY_OBJECT, - }, - ], + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); }); }); describe("#underline", () => { it("should set underline to 'single' if no arguments are given", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { underline: {}, @@ -351,7 +413,7 @@ describe("CharacterStyle", () => { }); it("should set the style if given", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { underline: { @@ -381,7 +443,7 @@ describe("CharacterStyle", () => { }); it("should set the style and color if given", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { underline: { @@ -412,8 +474,68 @@ describe("CharacterStyle", () => { }); }); + describe("#emphasisMark", () => { + it("should set emphasisMark to 'dot' if no arguments are given", () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { + emphasisMark: {}, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, + }, + }, + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); + }); + + it("should set the style if given", () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { + emphasisMark: { + type: EmphasisMarkType.DOT, + }, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, + }, + }, + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); + }); + }); + it("#superScript", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { superScript: true, @@ -449,7 +571,7 @@ describe("CharacterStyle", () => { }); it("#color", () => { - const style = new CharacterStyle({ + const style = new StyleForCharacter({ id: "myStyleId", run: { color: "123456", @@ -476,64 +598,96 @@ describe("CharacterStyle", () => { }); }); - it("#bold", () => { - const style = new CharacterStyle({ - id: "myStyleId", - run: { - bold: true, - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:b": { _attr: { "w:val": true } } }], - }, - { - "w:uiPriority": { - _attr: { - "w:val": 99, + const boldTests = [ + { + bold: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: false, + expected: [{ "w:b": { _attr: { "w:val": true } } }], + }, + ]; + boldTests.forEach(({ bold, boldComplexScript, expected }) => { + it(`#bold ${bold} cs ${boldComplexScript}`, () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { bold, boldComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": expected, + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, }, }, - }, - { - "w:unhideWhenUsed": EMPTY_OBJECT, - }, - ], + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); }); }); - it("#italics", () => { - const style = new CharacterStyle({ - id: "myStyleId", - run: { - italics: true, - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:i": { _attr: { "w:val": true } } }], - }, - { - "w:uiPriority": { - _attr: { - "w:val": 99, + const italicsTests = [ + { + italics: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: false, + expected: [{ "w:i": { _attr: { "w:val": true } } }], + }, + ]; + italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { + it(`#italics ${italics} cs ${italicsComplexScript}`, () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { italics, italicsComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": expected, + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, }, }, - }, - { - "w:unhideWhenUsed": EMPTY_OBJECT, - }, - ], + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); }); }); it("#link", () => { - const style = new CharacterStyle({ id: "myStyleId", link: "MyLink" }); + const style = new StyleForCharacter({ id: "myStyleId", link: "MyLink" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -554,7 +708,7 @@ describe("CharacterStyle", () => { }); it("#semiHidden", () => { - const style = new CharacterStyle({ id: "myStyleId", semiHidden: true }); + const style = new StyleForCharacter({ id: "myStyleId", semiHidden: true }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -572,63 +726,141 @@ describe("CharacterStyle", () => { }); }); - it("#highlight", () => { - const style = new CharacterStyle({ - id: "myStyleId", - run: { - highlight: "005599", - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }], - }, - { - "w:uiPriority": { - _attr: { - "w:val": 99, + const highlightTests = [ + { + highlight: "005599", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: true, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: false, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: "550099", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }], + }, + ]; + highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => { + it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { highlight, highlightComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": expected, + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, }, }, - }, - { - "w:unhideWhenUsed": EMPTY_OBJECT, - }, - ], + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); }); }); - it("#shadow", () => { - const style = new CharacterStyle({ - id: "myStyleId", - run: { - shadow: { - type: ShadingType.PERCENT_10, - fill: "00FFFF", - color: "FF0000", - }, + const shadingTests = [ + { + shadow: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], - }, - { - "w:uiPriority": { - _attr: { - "w:val": 99, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: true, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: false, + expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "00FF00", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } }, + ], + }, + ]; + shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => { + it("#shadow correctly", () => { + const style = new StyleForCharacter({ + id: "myStyleId", + run: { shadow, shading, shadingComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, + { + "w:rPr": expected, + }, + { + "w:uiPriority": { + _attr: { + "w:val": 99, + }, }, }, - }, - { - "w:unhideWhenUsed": EMPTY_OBJECT, - }, - ], + { + "w:unhideWhenUsed": EMPTY_OBJECT, + }, + ], + }); }); }); }); diff --git a/src/file/styles/style/character-style.ts b/src/file/styles/style/character-style.ts index 32ff4b6b69..63252bddd5 100644 --- a/src/file/styles/style/character-style.ts +++ b/src/file/styles/style/character-style.ts @@ -1,6 +1,4 @@ -import * as formatting from "file/paragraph/run/formatting"; -import { RunProperties } from "file/paragraph/run/properties"; -import { UnderlineType } from "file/paragraph/run/underline"; +import { IRunStylePropertiesOptions, RunProperties } from "file/paragraph/run/properties"; import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components"; import { Style } from "./style"; @@ -9,30 +7,7 @@ export interface IBaseCharacterStyleOptions { readonly basedOn?: string; readonly link?: string; readonly semiHidden?: boolean; - readonly run?: { - readonly size?: number; - readonly bold?: boolean; - readonly italics?: boolean; - readonly smallCaps?: boolean; - readonly allCaps?: boolean; - readonly strike?: boolean; - readonly doubleStrike?: boolean; - readonly subScript?: boolean; - readonly superScript?: boolean; - readonly underline?: { - readonly type?: UnderlineType; - readonly color?: string; - }; - readonly color?: string; - readonly font?: string; - readonly characterSpacing?: number; - readonly highlight?: string; - readonly shadow?: { - readonly type: string; - readonly fill: string; - readonly color: string; - }; - }; + readonly run?: IRunStylePropertiesOptions; } export interface ICharacterStyleOptions extends IBaseCharacterStyleOptions { @@ -40,12 +15,14 @@ export interface ICharacterStyleOptions extends IBaseCharacterStyleOptions { readonly name?: string; } -export class CharacterStyle extends Style { +export class StyleForCharacter extends Style { private readonly runProperties: RunProperties; constructor(options: ICharacterStyleOptions) { super({ type: "character", styleId: options.id }, options.name); - this.runProperties = new RunProperties(); + + this.runProperties = new RunProperties(options.run); + this.root.push(this.runProperties); this.root.push(new UiPriority(99)); this.root.push(new UnhideWhenUsed()); @@ -61,68 +38,5 @@ export class CharacterStyle extends Style { if (options.semiHidden) { this.root.push(new SemiHidden()); } - - if (options.run) { - if (options.run.size) { - this.runProperties.push(new formatting.Size(options.run.size)); - this.runProperties.push(new formatting.SizeComplexScript(options.run.size)); - } - - if (options.run.bold) { - this.runProperties.push(new formatting.Bold()); - } - - if (options.run.italics) { - this.runProperties.push(new formatting.Italics()); - } - - if (options.run.smallCaps) { - this.runProperties.push(new formatting.SmallCaps()); - } - - if (options.run.allCaps) { - this.runProperties.push(new formatting.Caps()); - } - - if (options.run.strike) { - this.runProperties.push(new formatting.Strike()); - } - - if (options.run.doubleStrike) { - this.runProperties.push(new formatting.DoubleStrike()); - } - - if (options.run.subScript) { - this.runProperties.push(new formatting.SubScript()); - } - - if (options.run.superScript) { - this.runProperties.push(new formatting.SuperScript()); - } - - if (options.run.underline) { - this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color)); - } - - if (options.run.color) { - this.runProperties.push(new formatting.Color(options.run.color)); - } - - if (options.run.font) { - this.runProperties.push(new formatting.RunFonts(options.run.font)); - } - - if (options.run.characterSpacing) { - this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing)); - } - - if (options.run.highlight) { - this.runProperties.push(new formatting.Highlight(options.run.highlight)); - } - - if (options.run.shadow) { - this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color)); - } - } } } diff --git a/src/file/styles/style/default-styles.spec.ts b/src/file/styles/style/default-styles.spec.ts index 1cf26ba482..962f47d9c0 100644 --- a/src/file/styles/style/default-styles.spec.ts +++ b/src/file/styles/style/default-styles.spec.ts @@ -120,6 +120,20 @@ describe("Default Styles", () => { }); }); + it("StrongStyle#constructor", () => { + const style = new defaultStyles.StrongStyle({}); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "paragraph", "w:styleId": "Strong" } }, + { "w:name": { _attr: { "w:val": "Strong" } } }, + { "w:basedOn": { _attr: { "w:val": "Normal" } } }, + { "w:next": { _attr: { "w:val": "Normal" } } }, + { "w:qFormat": EMPTY_OBJECT }, + ], + }); + }); + it("ListParagraph#constructor", () => { const style = new defaultStyles.ListParagraph({}); const tree = new Formatter().format(style); diff --git a/src/file/styles/style/default-styles.ts b/src/file/styles/style/default-styles.ts index 8974435a95..f8be7572ee 100644 --- a/src/file/styles/style/default-styles.ts +++ b/src/file/styles/style/default-styles.ts @@ -1,9 +1,9 @@ import { UnderlineType } from "file/paragraph/run/underline"; -import { CharacterStyle, IBaseCharacterStyleOptions } from "./character-style"; -import { IBaseParagraphStyleOptions, IParagraphStyleOptions, ParagraphStyle } from "./paragraph-style"; +import { IBaseCharacterStyleOptions, StyleForCharacter } from "./character-style"; +import { IBaseParagraphStyleOptions, IParagraphStyleOptions, StyleForParagraph } from "./paragraph-style"; -export class HeadingStyle extends ParagraphStyle { +export class HeadingStyle extends StyleForParagraph { constructor(options: IParagraphStyleOptions) { super({ ...options, @@ -84,7 +84,17 @@ export class Heading6Style extends HeadingStyle { } } -export class ListParagraph extends ParagraphStyle { +export class StrongStyle extends HeadingStyle { + constructor(options: IBaseParagraphStyleOptions) { + super({ + ...options, + id: "Strong", + name: "Strong", + }); + } +} + +export class ListParagraph extends StyleForParagraph { constructor(options: IBaseParagraphStyleOptions) { super({ ...options, @@ -96,7 +106,7 @@ export class ListParagraph extends ParagraphStyle { } } -export class FootnoteText extends ParagraphStyle { +export class FootnoteText extends StyleForParagraph { constructor(options: IBaseParagraphStyleOptions) { super({ ...options, @@ -121,7 +131,7 @@ export class FootnoteText extends ParagraphStyle { } } -export class FootnoteReferenceStyle extends CharacterStyle { +export class FootnoteReferenceStyle extends StyleForCharacter { constructor(options: IBaseCharacterStyleOptions) { super({ ...options, @@ -136,7 +146,7 @@ export class FootnoteReferenceStyle extends CharacterStyle { } } -export class FootnoteTextChar extends CharacterStyle { +export class FootnoteTextChar extends StyleForCharacter { constructor(options: IBaseCharacterStyleOptions) { super({ ...options, @@ -152,7 +162,7 @@ export class FootnoteTextChar extends CharacterStyle { } } -export class HyperlinkStyle extends CharacterStyle { +export class HyperlinkStyle extends StyleForCharacter { constructor(options: IBaseCharacterStyleOptions) { super({ ...options, diff --git a/src/file/styles/style/paragraph-style.spec.ts b/src/file/styles/style/paragraph-style.spec.ts index 93b0c6777c..8683234793 100644 --- a/src/file/styles/style/paragraph-style.spec.ts +++ b/src/file/styles/style/paragraph-style.spec.ts @@ -1,17 +1,17 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { AlignmentType, TabStopPosition } from "file/paragraph"; +import { AlignmentType, EmphasisMarkType, TabStopPosition } from "file/paragraph"; import { UnderlineType } from "file/paragraph/run/underline"; import { ShadingType } from "file/table"; import { EMPTY_OBJECT } from "file/xml-components"; -import { ParagraphStyle } from "./paragraph-style"; +import { StyleForParagraph } from "./paragraph-style"; describe("ParagraphStyle", () => { describe("#constructor", () => { it("should set the style type to paragraph and use the given style id", () => { - const style = new ParagraphStyle({ id: "myStyleId" }); + const style = new StyleForParagraph({ id: "myStyleId" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, @@ -19,7 +19,7 @@ describe("ParagraphStyle", () => { }); it("should set the name of the style, if given", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", name: "Style Name", }); @@ -35,7 +35,7 @@ describe("ParagraphStyle", () => { describe("formatting methods: style attributes", () => { it("#basedOn", () => { - const style = new ParagraphStyle({ id: "myStyleId", basedOn: "otherId" }); + const style = new StyleForParagraph({ id: "myStyleId", basedOn: "otherId" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -46,15 +46,23 @@ describe("ParagraphStyle", () => { }); it("#quickFormat", () => { - const style = new ParagraphStyle({ id: "myStyleId", quickFormat: true }); + const style = new StyleForParagraph({ id: "myStyleId", quickFormat: true }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:qFormat": EMPTY_OBJECT }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:qFormat": EMPTY_OBJECT }, + ], }); }); it("#next", () => { - const style = new ParagraphStyle({ id: "myStyleId", next: "otherId" }); + const style = new StyleForParagraph({ id: "myStyleId", next: "otherId" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -67,7 +75,7 @@ describe("ParagraphStyle", () => { describe("formatting methods: paragraph properties", () => { it("#indent", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { indent: { left: 720 }, @@ -85,7 +93,7 @@ describe("ParagraphStyle", () => { }); it("#spacing", () => { - const style = new ParagraphStyle({ id: "myStyleId", paragraph: { spacing: { before: 50, after: 150 } } }); + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { spacing: { before: 50, after: 150 } } }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -98,7 +106,7 @@ describe("ParagraphStyle", () => { }); it("#center", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { alignment: AlignmentType.CENTER, @@ -116,7 +124,7 @@ describe("ParagraphStyle", () => { }); it("#character spacing", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { characterSpacing: 24, @@ -134,7 +142,7 @@ describe("ParagraphStyle", () => { }); it("#left", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { alignment: AlignmentType.LEFT, @@ -152,7 +160,7 @@ describe("ParagraphStyle", () => { }); it("#right", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { alignment: AlignmentType.RIGHT, @@ -170,7 +178,7 @@ describe("ParagraphStyle", () => { }); it("#justified", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { alignment: AlignmentType.JUSTIFIED, @@ -188,7 +196,7 @@ describe("ParagraphStyle", () => { }); it("#thematicBreak", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { thematicBreak: true, @@ -220,8 +228,34 @@ describe("ParagraphStyle", () => { }); }); + it("#contextualSpacing", () => { + const style = new StyleForParagraph({ + id: "myStyleId", + paragraph: { + contextualSpacing: true, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, + { + "w:pPr": [ + { + "w:contextualSpacing": { + _attr: { + "w:val": 1, + }, + }, + }, + ], + }, + ], + }); + }); + it("#leftTabStop", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { leftTabStop: 1200, @@ -243,7 +277,7 @@ describe("ParagraphStyle", () => { }); it("#maxRightTabStop", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { rightTabStop: TabStopPosition.MAX, @@ -265,7 +299,7 @@ describe("ParagraphStyle", () => { }); it("#keepLines", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { keepLines: true, @@ -273,12 +307,20 @@ describe("ParagraphStyle", () => { }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }, + ], }); }); it("#keepNext", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { keepNext: true, @@ -286,12 +328,20 @@ describe("ParagraphStyle", () => { }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }, + ], }); }); it("#outlineLevel", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", paragraph: { outlineLevel: 1, @@ -308,26 +358,42 @@ describe("ParagraphStyle", () => { }); describe("formatting methods: run properties", () => { - it("#size", () => { - const style = new ParagraphStyle({ - id: "myStyleId", - run: { - size: 24, - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], - }, - ], + const sizeTests = [ + { + size: 24, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: true, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: false, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }], + }, + { + size: 24, + sizeComplexScript: 26, + expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }], + }, + ]; + sizeTests.forEach(({ size, sizeComplexScript, expected }) => { + it(`#size ${size} cs ${sizeComplexScript}`, () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { size, sizeComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }], + }); }); }); it("#smallCaps", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { smallCaps: true, @@ -345,7 +411,7 @@ describe("ParagraphStyle", () => { }); it("#allCaps", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { allCaps: true, @@ -363,7 +429,7 @@ describe("ParagraphStyle", () => { }); it("#strike", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { strike: true, @@ -381,7 +447,7 @@ describe("ParagraphStyle", () => { }); it("#doubleStrike", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { doubleStrike: true, @@ -399,7 +465,7 @@ describe("ParagraphStyle", () => { }); it("#subScript", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { subScript: true, @@ -417,7 +483,7 @@ describe("ParagraphStyle", () => { }); it("#superScript", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { superScript: true, @@ -434,8 +500,8 @@ describe("ParagraphStyle", () => { }); }); - it("#font", () => { - const style = new ParagraphStyle({ + it("#font by name", () => { + const style = new StyleForParagraph({ id: "myStyleId", run: { font: "Times", @@ -447,18 +513,30 @@ describe("ParagraphStyle", () => { { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": [ - { "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } }, + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:cs": "Times", + "w:eastAsia": "Times", + "w:hAnsi": "Times", + }, + }, + }, ], }, ], }); }); - it("#bold", () => { - const style = new ParagraphStyle({ + it("#font for ascii and eastAsia", () => { + const style = new StyleForParagraph({ id: "myStyleId", run: { - bold: true, + font: { + ascii: "Times", + eastAsia: "KaiTi", + }, }, }); const tree = new Formatter().format(style); @@ -466,73 +544,190 @@ describe("ParagraphStyle", () => { "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:b": { _attr: { "w:val": true } } }], + "w:rPr": [ + { + "w:rFonts": { + _attr: { + "w:ascii": "Times", + "w:eastAsia": "KaiTi", + }, + }, + }, + ], }, ], }); }); - it("#italics", () => { - const style = new ParagraphStyle({ - id: "myStyleId", - run: { - italics: true, - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:i": { _attr: { "w:val": true } } }], - }, - ], + const boldTests = [ + { + bold: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: true, + expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + }, + { + bold: true, + boldComplexScript: false, + expected: [{ "w:b": { _attr: { "w:val": true } } }], + }, + ]; + boldTests.forEach(({ bold, boldComplexScript, expected }) => { + it(`#bold ${bold} cs ${boldComplexScript}`, () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { bold, boldComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }], + }); }); }); - it("#highlight", () => { - const style = new ParagraphStyle({ - id: "myStyleId", - run: { - highlight: "005599", - }, - }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }], - }, - ], + const italicsTests = [ + { + italics: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: true, + expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + }, + { + italics: true, + italicsComplexScript: false, + expected: [{ "w:i": { _attr: { "w:val": true } } }], + }, + ]; + italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { + it(`#italics ${italics} cs ${italicsComplexScript}`, () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { italics, italicsComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }], + }); }); }); - it("#shadow", () => { - const style = new ParagraphStyle({ - id: "myStyleId", - run: { - shadow: { - type: ShadingType.PERCENT_10, - fill: "00FFFF", - color: "FF0000", - }, - }, + const highlightTests = [ + { + highlight: "005599", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: true, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: false, + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }], + }, + { + highlight: "005599", + highlightComplexScript: "550099", + expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }], + }, + ]; + highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => { + it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { highlight, highlightComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }], + }); }); - const tree = new Formatter().format(style); - expect(tree).to.deep.equal({ - "w:style": [ - { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, - { - "w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], - }, + }); + + const shadingTests = [ + { + shadow: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: true, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + ], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: false, + expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }], + }, + { + shading: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "FF0000", + }, + shadingComplexScript: { + type: ShadingType.PERCENT_10, + fill: "00FFFF", + color: "00FF00", + }, + expected: [ + { "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }, + { "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } }, + ], + }, + ]; + shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => { + it("#shadow correctly", () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { shadow, shading, shadingComplexScript }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }], + }); }); }); describe("#underline", () => { it("should set underline to 'single' if no arguments are given", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { underline: {}, @@ -550,7 +745,7 @@ describe("ParagraphStyle", () => { }); it("should set the style if given", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { underline: { @@ -570,7 +765,7 @@ describe("ParagraphStyle", () => { }); it("should set the style and color if given", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { underline: { @@ -591,8 +786,48 @@ describe("ParagraphStyle", () => { }); }); + describe("#emphasisMark", () => { + it("should set emphasisMark to 'dot' if no arguments are given", () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { + emphasisMark: {}, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, + { + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }, + ], + }); + }); + + it("should set the style if given", () => { + const style = new StyleForParagraph({ + id: "myStyleId", + run: { + emphasisMark: { + type: EmphasisMarkType.DOT, + }, + }, + }); + const tree = new Formatter().format(style); + expect(tree).to.deep.equal({ + "w:style": [ + { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, + { + "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }], + }, + ], + }); + }); + }); + it("#color", () => { - const style = new ParagraphStyle({ + const style = new StyleForParagraph({ id: "myStyleId", run: { color: "123456", @@ -610,23 +845,39 @@ describe("ParagraphStyle", () => { }); it("#link", () => { - const style = new ParagraphStyle({ id: "myStyleId", link: "MyLink" }); + const style = new StyleForParagraph({ id: "myStyleId", link: "MyLink" }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:link": { _attr: { "w:val": "MyLink" } } }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:link": { _attr: { "w:val": "MyLink" } } }, + ], }); }); it("#semiHidden", () => { - const style = new ParagraphStyle({ id: "myStyleId", semiHidden: true }); + const style = new StyleForParagraph({ id: "myStyleId", semiHidden: true }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:semiHidden": EMPTY_OBJECT }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:semiHidden": EMPTY_OBJECT }, + ], }); }); it("#uiPriority", () => { - const style = new ParagraphStyle({ id: "myStyleId", uiPriority: 99 }); + const style = new StyleForParagraph({ id: "myStyleId", uiPriority: 99 }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ @@ -643,10 +894,18 @@ describe("ParagraphStyle", () => { }); it("#unhideWhenUsed", () => { - const style = new ParagraphStyle({ id: "myStyleId", unhideWhenUsed: true }); + const style = new StyleForParagraph({ id: "myStyleId", unhideWhenUsed: true }); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ - "w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:unhideWhenUsed": EMPTY_OBJECT }], + "w:style": [ + { + _attr: { + "w:type": "paragraph", + "w:styleId": "myStyleId", + }, + }, + { "w:unhideWhenUsed": EMPTY_OBJECT }, + ], }); }); }); diff --git a/src/file/styles/style/paragraph-style.ts b/src/file/styles/style/paragraph-style.ts index ab592a9fc6..25c035e514 100644 --- a/src/file/styles/style/paragraph-style.ts +++ b/src/file/styles/style/paragraph-style.ts @@ -1,20 +1,5 @@ -import { - Alignment, - AlignmentType, - Indent, - ISpacingProperties, - KeepLines, - KeepNext, - OutlineLevel, - ParagraphProperties, - Spacing, - ThematicBreak, -} from "file/paragraph"; -import { IIndentAttributesProperties, TabStop, TabStopType } from "file/paragraph/formatting"; -import * as formatting from "file/paragraph/run/formatting"; +import { IParagraphStylePropertiesOptions, IRunStylePropertiesOptions, ParagraphProperties } from "file/paragraph"; import { RunProperties } from "file/paragraph/run/properties"; -import { UnderlineType } from "file/paragraph/run/underline"; -import { ShadingType } from "file/table"; import { BasedOn, Link, Next, QuickFormat, SemiHidden, UiPriority, UnhideWhenUsed } from "./components"; import { Style } from "./style"; @@ -27,55 +12,25 @@ export interface IBaseParagraphStyleOptions { readonly semiHidden?: boolean; readonly uiPriority?: number; readonly unhideWhenUsed?: boolean; - readonly run?: { - readonly size?: number; - readonly bold?: boolean; - readonly italics?: boolean; - readonly smallCaps?: boolean; - readonly allCaps?: boolean; - readonly strike?: boolean; - readonly doubleStrike?: boolean; - readonly subScript?: boolean; - readonly superScript?: boolean; - readonly underline?: { - readonly type?: UnderlineType; - readonly color?: string; - }; - readonly color?: string; - readonly font?: string; - readonly characterSpacing?: number; - readonly highlight?: string; - readonly shadow?: { - readonly type: ShadingType; - readonly fill: string; - readonly color: string; - }; - }; - readonly paragraph?: { - readonly alignment?: AlignmentType; - readonly thematicBreak?: boolean; - readonly rightTabStop?: number; - readonly leftTabStop?: number; - readonly indent?: IIndentAttributesProperties; - readonly spacing?: ISpacingProperties; - readonly keepNext?: boolean; - readonly keepLines?: boolean; - readonly outlineLevel?: number; - }; + readonly paragraph?: IParagraphStylePropertiesOptions; + readonly run?: IRunStylePropertiesOptions; } export interface IParagraphStyleOptions extends IBaseParagraphStyleOptions { readonly id: string; readonly name?: string; } -export class ParagraphStyle extends Style { + +export class StyleForParagraph extends Style { private readonly paragraphProperties: ParagraphProperties; private readonly runProperties: RunProperties; constructor(options: IParagraphStyleOptions) { super({ type: "paragraph", styleId: options.id }, options.name); - this.paragraphProperties = new ParagraphProperties({}); - this.runProperties = new RunProperties(); + + this.paragraphProperties = new ParagraphProperties(options.paragraph); + this.runProperties = new RunProperties(options.run); + this.root.push(this.paragraphProperties); this.root.push(this.runProperties); @@ -106,106 +61,5 @@ export class ParagraphStyle extends Style { if (options.unhideWhenUsed) { this.root.push(new UnhideWhenUsed()); } - - if (options.run) { - if (options.run.size) { - this.runProperties.push(new formatting.Size(options.run.size)); - this.runProperties.push(new formatting.SizeComplexScript(options.run.size)); - } - - if (options.run.bold) { - this.runProperties.push(new formatting.Bold()); - } - - if (options.run.italics) { - this.runProperties.push(new formatting.Italics()); - } - - if (options.run.smallCaps) { - this.runProperties.push(new formatting.SmallCaps()); - } - - if (options.run.allCaps) { - this.runProperties.push(new formatting.Caps()); - } - - if (options.run.strike) { - this.runProperties.push(new formatting.Strike()); - } - - if (options.run.doubleStrike) { - this.runProperties.push(new formatting.DoubleStrike()); - } - - if (options.run.subScript) { - this.runProperties.push(new formatting.SubScript()); - } - - if (options.run.superScript) { - this.runProperties.push(new formatting.SuperScript()); - } - - if (options.run.underline) { - this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color)); - } - - if (options.run.color) { - this.runProperties.push(new formatting.Color(options.run.color)); - } - - if (options.run.font) { - this.runProperties.push(new formatting.RunFonts(options.run.font)); - } - - if (options.run.characterSpacing) { - this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing)); - } - - if (options.run.highlight) { - this.runProperties.push(new formatting.Highlight(options.run.highlight)); - } - - if (options.run.shadow) { - this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color)); - } - } - - if (options.paragraph) { - if (options.paragraph.alignment) { - this.paragraphProperties.push(new Alignment(options.paragraph.alignment)); - } - - if (options.paragraph.thematicBreak) { - this.paragraphProperties.push(new ThematicBreak()); - } - - if (options.paragraph.rightTabStop) { - this.paragraphProperties.push(new TabStop(TabStopType.RIGHT, options.paragraph.rightTabStop)); - } - - if (options.paragraph.leftTabStop) { - this.paragraphProperties.push(new TabStop(TabStopType.LEFT, options.paragraph.leftTabStop)); - } - - if (options.paragraph.indent) { - this.paragraphProperties.push(new Indent(options.paragraph.indent)); - } - - if (options.paragraph.spacing) { - this.paragraphProperties.push(new Spacing(options.paragraph.spacing)); - } - - if (options.paragraph.keepNext) { - this.paragraphProperties.push(new KeepNext()); - } - - if (options.paragraph.keepLines) { - this.paragraphProperties.push(new KeepLines()); - } - - if (options.paragraph.outlineLevel) { - this.paragraphProperties.push(new OutlineLevel(options.paragraph.outlineLevel)); - } - } } } diff --git a/src/file/styles/styles.ts b/src/file/styles/styles.ts index 064411e419..1906b45ba0 100644 --- a/src/file/styles/styles.ts +++ b/src/file/styles/styles.ts @@ -1,15 +1,16 @@ +import { IDefaultStylesOptions } from "file/styles/factory"; import { BaseXmlComponent, ImportedXmlComponent, XmlComponent } from "file/xml-components"; - -import { CharacterStyle, ParagraphStyle } from "./style"; +import { StyleForCharacter, StyleForParagraph } from "./style"; import { ICharacterStyleOptions } from "./style/character-style"; import { IParagraphStyleOptions } from "./style/paragraph-style"; export * from "./border"; export interface IStylesOptions { + readonly default?: IDefaultStylesOptions; readonly initialStyles?: BaseXmlComponent; readonly paragraphStyles?: IParagraphStyleOptions[]; readonly characterStyles?: ICharacterStyleOptions[]; - readonly importedStyles?: Array; + readonly importedStyles?: (XmlComponent | StyleForParagraph | StyleForCharacter | ImportedXmlComponent)[]; } export class Styles extends XmlComponent { @@ -28,13 +29,13 @@ export class Styles extends XmlComponent { if (options.paragraphStyles) { for (const style of options.paragraphStyles) { - this.root.push(new ParagraphStyle(style)); + this.root.push(new StyleForParagraph(style)); } } if (options.characterStyles) { for (const style of options.characterStyles) { - this.root.push(new CharacterStyle(style)); + this.root.push(new StyleForCharacter(style)); } } } diff --git a/src/file/table/table-cell/table-cell-components.ts b/src/file/table/table-cell/table-cell-components.ts index e16c2f6885..f3ebe570e9 100644 --- a/src/file/table/table-cell/table-cell-components.ts +++ b/src/file/table/table-cell/table-cell-components.ts @@ -158,6 +158,31 @@ export class VAlign extends XmlComponent { } } +export enum TextDirection { + BOTTOM_TO_TOP_LEFT_TO_RIGHT = "btLr", + LEFT_TO_RIGHT_TOP_TO_BOTTOM = "lrTb", + TOP_TO_BOTTOM_RIGHT_TO_LEFT = "tbRl", +} + +class TDirectionAttributes extends XmlAttributeComponent<{ readonly val: TextDirection }> { + protected readonly xmlKeys = { val: "w:val" }; +} + +/** + * Text Direction within a table cell + */ +export class TDirection extends XmlComponent { + constructor(value: TextDirection) { + super("w:textDirection"); + + this.root.push( + new TDirectionAttributes({ + val: value, + }), + ); + } +} + export enum WidthType { /** Auto. */ AUTO = "auto", diff --git a/src/file/table/table-cell/table-cell-properties.ts b/src/file/table/table-cell/table-cell-properties.ts index aed56aaeda..e248290294 100644 --- a/src/file/table/table-cell/table-cell-properties.ts +++ b/src/file/table/table-cell/table-cell-properties.ts @@ -6,6 +6,8 @@ import { GridSpan, TableCellBorders, TableCellWidth, + TDirection, + TextDirection, VAlign, VerticalAlign, VerticalMerge, @@ -61,4 +63,10 @@ export class TableCellProperties extends IgnoreIfEmptyXmlComponent { return this; } + + public setTextDirection(type: TextDirection): TableCellProperties { + this.root.push(new TDirection(type)); + + return this; + } } diff --git a/src/file/table/table-cell/table-cell.spec.ts b/src/file/table/table-cell/table-cell.spec.ts index 4dd86ffc9c..2ba34bc9d4 100644 --- a/src/file/table/table-cell/table-cell.spec.ts +++ b/src/file/table/table-cell/table-cell.spec.ts @@ -5,7 +5,7 @@ import { BorderStyle } from "file/styles"; import { ShadingType } from "../shading"; import { TableCell } from "./table-cell"; -import { TableCellBorders, TableCellWidth, VerticalAlign, VerticalMergeType, WidthType } from "./table-cell-components"; +import { TableCellBorders, TableCellWidth, TextDirection, VerticalAlign, VerticalMergeType, WidthType } from "./table-cell-components"; describe("TableCellBorders", () => { describe("#prepForXml", () => { @@ -271,6 +271,34 @@ describe("TableCell", () => { }); }); + it("should create with text direction", () => { + const cell = new TableCell({ + children: [], + textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT, + }); + + const tree = new Formatter().format(cell); + + expect(tree).to.deep.equal({ + "w:tc": [ + { + "w:tcPr": [ + { + "w:textDirection": { + _attr: { + "w:val": "btLr", + }, + }, + }, + ], + }, + { + "w:p": {}, + }, + ], + }); + }); + it("should create with vertical merge", () => { const cell = new TableCell({ children: [], @@ -395,6 +423,33 @@ describe("TableCell", () => { }); }); + it("should create with width", () => { + const cell = new TableCell({ + children: [], + width: { size: 100, type: WidthType.DXA }, + }); + const tree = new Formatter().format(cell); + expect(tree).to.deep.equal({ + "w:tc": [ + { + "w:tcPr": [ + { + "w:tcW": { + _attr: { + "w:type": "dxa", + "w:w": 100, + }, + }, + }, + ], + }, + { + "w:p": {}, + }, + ], + }); + }); + it("should create with column span", () => { const cell = new TableCell({ children: [], diff --git a/src/file/table/table-cell/table-cell.ts b/src/file/table/table-cell/table-cell.ts index 5c34d17903..9c8e8efd58 100644 --- a/src/file/table/table-cell/table-cell.ts +++ b/src/file/table/table-cell/table-cell.ts @@ -1,4 +1,5 @@ // http://officeopenxml.com/WPtableGrid.php +import { IViewWrapper } from "file/document-wrapper"; import { Paragraph } from "file/paragraph"; import { BorderStyle } from "file/styles"; import { IXmlableObject, XmlComponent } from "file/xml-components"; @@ -6,14 +7,19 @@ import { IXmlableObject, XmlComponent } from "file/xml-components"; import { ITableShadingAttributesProperties } from "../shading"; import { Table } from "../table"; import { ITableCellMarginOptions } from "./cell-margin/table-cell-margins"; -import { VerticalAlign, VerticalMergeType } from "./table-cell-components"; +import { TextDirection, VerticalAlign, VerticalMergeType, WidthType } from "./table-cell-components"; import { TableCellProperties } from "./table-cell-properties"; export interface ITableCellOptions { readonly shading?: ITableShadingAttributesProperties; readonly margins?: ITableCellMarginOptions; readonly verticalAlign?: VerticalAlign; + readonly textDirection?: TextDirection; readonly verticalMerge?: VerticalMergeType; + readonly width?: { + readonly size: number | string; + readonly type?: WidthType; + }; readonly columnSpan?: number; readonly rowSpan?: number; readonly borders?: { @@ -38,75 +44,72 @@ export interface ITableCellOptions { readonly color: string; }; }; - readonly children: Array; + readonly children: (Paragraph | Table)[]; } export class TableCell extends XmlComponent { - private readonly properties: TableCellProperties; - constructor(readonly options: ITableCellOptions) { super("w:tc"); - this.properties = new TableCellProperties(); - this.root.push(this.properties); + const properties = new TableCellProperties(); + this.root.push(properties); for (const child of options.children) { this.root.push(child); } if (options.verticalAlign) { - this.properties.setVerticalAlign(options.verticalAlign); + properties.setVerticalAlign(options.verticalAlign); + } + + if (options.textDirection) { + properties.setTextDirection(options.textDirection); } if (options.verticalMerge) { - this.properties.addVerticalMerge(options.verticalMerge); + properties.addVerticalMerge(options.verticalMerge); + } else if (options.rowSpan && options.rowSpan > 1) { + // if cell already have a `verticalMerge`, don't handle `rowSpan` + properties.addVerticalMerge(VerticalMergeType.RESTART); } if (options.margins) { - this.properties.addMargins(options.margins); + properties.addMargins(options.margins); } if (options.shading) { - this.properties.setShading(options.shading); + properties.setShading(options.shading); } if (options.columnSpan) { - this.properties.addGridSpan(options.columnSpan); + properties.addGridSpan(options.columnSpan); } - if (options.rowSpan && options.rowSpan > 1) { - this.properties.addVerticalMerge(VerticalMergeType.RESTART); + if (options.width) { + properties.setWidth(options.width.size, options.width.type); } if (options.borders) { if (options.borders.top) { - this.properties.Borders.addTopBorder(options.borders.top.style, options.borders.top.size, options.borders.top.color); + properties.Borders.addTopBorder(options.borders.top.style, options.borders.top.size, options.borders.top.color); } if (options.borders.bottom) { - this.properties.Borders.addBottomBorder( - options.borders.bottom.style, - options.borders.bottom.size, - options.borders.bottom.color, - ); + properties.Borders.addBottomBorder(options.borders.bottom.style, options.borders.bottom.size, options.borders.bottom.color); } if (options.borders.left) { - this.properties.Borders.addLeftBorder(options.borders.left.style, options.borders.left.size, options.borders.left.color); + properties.Borders.addLeftBorder(options.borders.left.style, options.borders.left.size, options.borders.left.color); } if (options.borders.right) { - this.properties.Borders.addRightBorder( - options.borders.right.style, - options.borders.right.size, - options.borders.right.color, - ); + properties.Borders.addRightBorder(options.borders.right.style, options.borders.right.size, options.borders.right.color); } } } - public prepForXml(): IXmlableObject | undefined { + public prepForXml(file?: IViewWrapper): IXmlableObject | undefined { // Cells must end with a paragraph if (!(this.root[this.root.length - 1] instanceof Paragraph)) { this.root.push(new Paragraph({})); } - return super.prepForXml(); + return super.prepForXml(file); } } diff --git a/src/file/table/table-properties/index.ts b/src/file/table/table-properties/index.ts index dde973ee7a..c5b5935d7f 100644 --- a/src/file/table/table-properties/index.ts +++ b/src/file/table/table-properties/index.ts @@ -1,3 +1,5 @@ export * from "./table-properties"; export * from "./table-float-properties"; export * from "./table-layout"; +export * from "./table-borders"; +export * from "./table-overlap"; diff --git a/src/file/table/table-properties/table-borders.spec.ts b/src/file/table/table-properties/table-borders.spec.ts new file mode 100644 index 0000000000..4a3212feb1 --- /dev/null +++ b/src/file/table/table-properties/table-borders.spec.ts @@ -0,0 +1,622 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { BorderStyle } from "file/styles"; + +import { TableBorders } from "./table-borders"; + +describe("TableBorders", () => { + describe("#constructor", () => { + describe("default borders", () => { + it("should add a table cell top border using default width type", () => { + const tableBorders = new TableBorders({}); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("top border", () => { + it("should add a table cell top border", () => { + const tableBorders = new TableBorders({ + top: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + + const tree = new Formatter().format(tableBorders); + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("left border", () => { + it("should add a table cell left border", () => { + const tableBorders = new TableBorders({ + left: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("bottom border", () => { + it("should add a table cell bottom border", () => { + const tableBorders = new TableBorders({ + bottom: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("right border", () => { + it("should add a table cell right border", () => { + const tableBorders = new TableBorders({ + right: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("inside horizontal border", () => { + it("should add a table cell inside horizontal border", () => { + const tableBorders = new TableBorders({ + insideHorizontal: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + ], + }); + }); + }); + + describe("inside vertical border", () => { + it("should add a table cell inside horizontal border", () => { + const tableBorders = new TableBorders({ + insideVertical: { + style: BorderStyle.DOUBLE, + size: 1, + color: "red", + }, + }); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 4, + "w:val": "single", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "red", + "w:space": 0, + "w:sz": 1, + "w:val": "double", + }, + }, + }, + ], + }); + }); + }); + + describe("TableBorders.NONE convenience object", () => { + it("should add no borders", () => { + const tableBorders = new TableBorders(TableBorders.NONE); + const tree = new Formatter().format(tableBorders); + + expect(tree).to.deep.equal({ + "w:tblBorders": [ + { + "w:top": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + { + "w:left": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + { + "w:bottom": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + { + "w:right": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + { + "w:insideH": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + { + "w:insideV": { + _attr: { + "w:color": "auto", + "w:space": 0, + "w:sz": 0, + "w:val": "none", + }, + }, + }, + ], + }); + }); + }); + }); +}); diff --git a/src/file/table/table-properties/table-borders.ts b/src/file/table/table-properties/table-borders.ts index 204bccf496..8de354fc36 100644 --- a/src/file/table/table-properties/table-borders.ts +++ b/src/file/table/table-properties/table-borders.ts @@ -1,14 +1,128 @@ +// http://officeopenxml.com/WPtableBorders.php +import { BorderStyle } from "file/styles"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; +export interface ITableBordersOptions { + readonly top?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly bottom?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly left?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly right?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly insideHorizontal?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly insideVertical?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; +} + export class TableBorders extends XmlComponent { - constructor() { + public static readonly NONE = { + top: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + bottom: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + left: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + right: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + insideHorizontal: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + insideVertical: { + style: BorderStyle.NONE, + size: 0, + color: "auto", + }, + }; + + constructor(options: ITableBordersOptions) { super("w:tblBorders"); - this.root.push(new TableBordersElement("w:top", "single", 4, 0, "auto")); - this.root.push(new TableBordersElement("w:left", "single", 4, 0, "auto")); - this.root.push(new TableBordersElement("w:bottom", "single", 4, 0, "auto")); - this.root.push(new TableBordersElement("w:right", "single", 4, 0, "auto")); - this.root.push(new TableBordersElement("w:insideH", "single", 4, 0, "auto")); - this.root.push(new TableBordersElement("w:insideV", "single", 4, 0, "auto")); + + if (options.top) { + this.root.push(new TableBordersElement("w:top", options.top.style, options.top.size, 0, options.top.color)); + } else { + this.root.push(new TableBordersElement("w:top", BorderStyle.SINGLE, 4, 0, "auto")); + } + + if (options.left) { + this.root.push(new TableBordersElement("w:left", options.left.style, options.left.size, 0, options.left.color)); + } else { + this.root.push(new TableBordersElement("w:left", BorderStyle.SINGLE, 4, 0, "auto")); + } + + if (options.bottom) { + this.root.push(new TableBordersElement("w:bottom", options.bottom.style, options.bottom.size, 0, options.bottom.color)); + } else { + this.root.push(new TableBordersElement("w:bottom", BorderStyle.SINGLE, 4, 0, "auto")); + } + + if (options.right) { + this.root.push(new TableBordersElement("w:right", options.right.style, options.right.size, 0, options.right.color)); + } else { + this.root.push(new TableBordersElement("w:right", BorderStyle.SINGLE, 4, 0, "auto")); + } + + if (options.insideHorizontal) { + this.root.push( + new TableBordersElement( + "w:insideH", + options.insideHorizontal.style, + options.insideHorizontal.size, + 0, + options.insideHorizontal.color, + ), + ); + } else { + this.root.push(new TableBordersElement("w:insideH", BorderStyle.SINGLE, 4, 0, "auto")); + } + + if (options.insideVertical) { + this.root.push( + new TableBordersElement( + "w:insideV", + options.insideVertical.style, + options.insideVertical.size, + 0, + options.insideVertical.color, + ), + ); + } else { + this.root.push(new TableBordersElement("w:insideV", BorderStyle.SINGLE, 4, 0, "auto")); + } } } diff --git a/src/file/table/table-properties/table-cell-margin.spec.ts b/src/file/table/table-properties/table-cell-margin.spec.ts index 2a89db7a4a..814888adc0 100644 --- a/src/file/table/table-properties/table-cell-margin.spec.ts +++ b/src/file/table/table-properties/table-cell-margin.spec.ts @@ -8,22 +8,31 @@ import { TableCellMargin } from "./table-cell-margin"; describe("TableCellMargin", () => { describe("#constructor", () => { it("should throw an error if theres no child elements", () => { - const cellMargin = new TableCellMargin(); + const cellMargin = new TableCellMargin({}); expect(() => new Formatter().format(cellMargin)).to.throw(); }); }); describe("#addTopMargin", () => { it("should add a table cell top margin", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addTopMargin(1234, WidthType.DXA); + const cellMargin = new TableCellMargin({ + top: { + value: 1234, + type: WidthType.DXA, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); it("should add a table cell top margin using default width type", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addTopMargin(1234); + const cellMargin = new TableCellMargin({ + top: { + value: 1234, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); @@ -31,15 +40,22 @@ describe("TableCellMargin", () => { describe("#addLeftMargin", () => { it("should add a table cell left margin", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addLeftMargin(1234, WidthType.DXA); + const cellMargin = new TableCellMargin({ + left: { + value: 1234, + type: WidthType.DXA, + }, + }); const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); it("should add a table cell left margin using default width type", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addLeftMargin(1234); + const cellMargin = new TableCellMargin({ + left: { + value: 1234, + }, + }); const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); @@ -47,15 +63,24 @@ describe("TableCellMargin", () => { describe("#addBottomMargin", () => { it("should add a table cell bottom margin", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addBottomMargin(1234, WidthType.DXA); + const cellMargin = new TableCellMargin({ + bottom: { + value: 1234, + type: WidthType.DXA, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); it("should add a table cell bottom margin using default width type", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addBottomMargin(1234); + const cellMargin = new TableCellMargin({ + bottom: { + value: 1234, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); @@ -63,15 +88,24 @@ describe("TableCellMargin", () => { describe("#addRightMargin", () => { it("should add a table cell right margin", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addRightMargin(1234, WidthType.DXA); + const cellMargin = new TableCellMargin({ + right: { + value: 1234, + type: WidthType.DXA, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); it("should add a table cell right margin using default width type", () => { - const cellMargin = new TableCellMargin(); - cellMargin.addRightMargin(1234); + const cellMargin = new TableCellMargin({ + right: { + value: 1234, + }, + }); + const tree = new Formatter().format(cellMargin); expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }); }); diff --git a/src/file/table/table-properties/table-cell-margin.ts b/src/file/table/table-properties/table-cell-margin.ts index ebebb87bc3..6889b6f580 100644 --- a/src/file/table/table-properties/table-cell-margin.ts +++ b/src/file/table/table-properties/table-cell-margin.ts @@ -6,7 +6,23 @@ class TableCellMarginAttributes extends XmlAttributeComponent<{ readonly type: W protected readonly xmlKeys = { value: "w:w", type: "w:type" }; } +interface IBaseTableCellMarginOptions { + readonly value: number; + readonly type?: WidthType; +} + class BaseTableCellMargin extends XmlComponent { + constructor(rootKey: string, options: IBaseTableCellMarginOptions) { + super(rootKey); + + this.root.push( + new TableCellMarginAttributes({ + type: options.type ?? WidthType.DXA, + value: options.value, + }), + ); + } + public setProperties(value: number, type: WidthType = WidthType.DXA): void { this.root.push( new TableCellMarginAttributes({ @@ -17,36 +33,31 @@ class BaseTableCellMargin extends XmlComponent { } } +export interface ITableCellMarginOptions { + readonly top?: IBaseTableCellMarginOptions; + readonly bottom?: IBaseTableCellMarginOptions; + readonly left?: IBaseTableCellMarginOptions; + readonly right?: IBaseTableCellMarginOptions; +} + export class TableCellMargin extends IgnoreIfEmptyXmlComponent { - constructor() { + constructor(options: ITableCellMarginOptions) { super("w:tblCellMar"); - } - public addTopMargin(value: number, type: WidthType = WidthType.DXA): void { - const top = new BaseTableCellMargin("w:top"); + if (options.bottom) { + this.root.push(new BaseTableCellMargin("w:bottom", options.bottom)); + } - top.setProperties(value, type); - this.root.push(top); - } + if (options.top) { + this.root.push(new BaseTableCellMargin("w:top", options.top)); + } - public addLeftMargin(value: number, type: WidthType = WidthType.DXA): void { - const left = new BaseTableCellMargin("w:left"); + if (options.left) { + this.root.push(new BaseTableCellMargin("w:left", options.left)); + } - left.setProperties(value, type); - this.root.push(left); - } - - public addBottomMargin(value: number, type: WidthType = WidthType.DXA): void { - const bottom = new BaseTableCellMargin("w:bottom"); - - bottom.setProperties(value, type); - this.root.push(bottom); - } - - public addRightMargin(value: number, type: WidthType = WidthType.DXA): void { - const right = new BaseTableCellMargin("w:right"); - - right.setProperties(value, type); - this.root.push(right); + if (options.right) { + this.root.push(new BaseTableCellMargin("w:right", options.right)); + } } } diff --git a/src/file/table/table-properties/table-float-properties.spec.ts b/src/file/table/table-properties/table-float-properties.spec.ts index a1422d871b..10d38f31f3 100644 --- a/src/file/table/table-properties/table-float-properties.spec.ts +++ b/src/file/table/table-properties/table-float-properties.spec.ts @@ -3,11 +3,12 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType, TableFloatProperties } from "./table-float-properties"; +import { OverlapType } from "./table-overlap"; describe("Table Float Properties", () => { describe("#constructor", () => { it("should construct a TableFloatProperties with all options", () => { - const tfp = new TableFloatProperties({ + const properties = new TableFloatProperties({ horizontalAnchor: TableAnchorType.MARGIN, verticalAnchor: TableAnchorType.PAGE, absoluteHorizontalPosition: 10, @@ -19,8 +20,32 @@ describe("Table Float Properties", () => { leftFromText: 50, rightFromText: 60, }); - const tree = new Formatter().format(tfp); - expect(tree).to.be.deep.equal(DEFAULT_TFP); + const tree = new Formatter().format(properties); + expect(tree).to.deep.equal(DEFAULT_TFP); + }); + + it("should add overlap", () => { + const properties = new TableFloatProperties({ + overlap: OverlapType.NEVER, + }); + const tree = new Formatter().format(properties); + + expect(tree).to.deep.equal({ + "w:tblpPr": [ + { + _attr: { + overlap: "never", + }, + }, + { + "w:tblOverlap": { + _attr: { + "w:val": "never", + }, + }, + }, + ], + }); }); }); }); diff --git a/src/file/table/table-properties/table-float-properties.ts b/src/file/table/table-properties/table-float-properties.ts index a1053c4ab2..2b97d86c1c 100644 --- a/src/file/table/table-properties/table-float-properties.ts +++ b/src/file/table/table-properties/table-float-properties.ts @@ -1,5 +1,7 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; +import { OverlapType, TableOverlap } from "./table-overlap"; + export enum TableAnchorType { MARGIN = "margin", PAGE = "page", @@ -109,6 +111,7 @@ export interface ITableFloatOptions { * to the right of the table. The value is in twentieths of a point. If omitted, the value is assumed to be zero. */ readonly rightFromText?: number; + readonly overlap?: OverlapType; } export class TableFloatOptionsAttributes extends XmlAttributeComponent { @@ -130,5 +133,9 @@ export class TableFloatProperties extends XmlComponent { constructor(options: ITableFloatOptions) { super("w:tblpPr"); this.root.push(new TableFloatOptionsAttributes(options)); + + if (options.overlap) { + this.root.push(new TableOverlap(options.overlap)); + } } } diff --git a/src/file/table/table-properties/table-overlap.spec.ts b/src/file/table/table-properties/table-overlap.spec.ts new file mode 100644 index 0000000000..80ddd13e3d --- /dev/null +++ b/src/file/table/table-properties/table-overlap.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; + +import { OverlapType, TableOverlap } from "./table-overlap"; + +describe("TableOverlap", () => { + describe("#constructor", () => { + it("sets the width attribute to the value given", () => { + const tableOverlap = new TableOverlap(OverlapType.OVERLAP); + const tree = new Formatter().format(tableOverlap); + + expect(tree).to.deep.equal({ + "w:tblOverlap": { + _attr: { + "w:val": "overlap", + }, + }, + }); + }); + }); +}); diff --git a/src/file/table/table-properties/table-overlap.ts b/src/file/table/table-properties/table-overlap.ts new file mode 100644 index 0000000000..387cf27943 --- /dev/null +++ b/src/file/table/table-properties/table-overlap.ts @@ -0,0 +1,17 @@ +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +export enum OverlapType { + NEVER = "never", + OVERLAP = "overlap", +} + +class TableOverlapAttributes extends XmlAttributeComponent<{ readonly val: OverlapType }> { + protected readonly xmlKeys = { val: "w:val" }; +} + +export class TableOverlap extends XmlComponent { + constructor(type: OverlapType) { + super("w:tblOverlap"); + this.root.push(new TableOverlapAttributes({ val: type })); + } +} diff --git a/src/file/table/table-properties/table-properties.spec.ts b/src/file/table/table-properties/table-properties.spec.ts index 88f7abde4e..49ff9f740e 100644 --- a/src/file/table/table-properties/table-properties.spec.ts +++ b/src/file/table/table-properties/table-properties.spec.ts @@ -2,6 +2,7 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; +import { AlignmentType } from "../../paragraph"; import { ShadingType } from "../shading"; import { WidthType } from "../table-cell"; import { TableLayoutType } from "./table-layout"; @@ -10,7 +11,7 @@ import { TableProperties } from "./table-properties"; describe("TableProperties", () => { describe("#constructor", () => { it("creates an initially empty property object", () => { - const tp = new TableProperties(); + const tp = new TableProperties({}); // The TableProperties is ignorable if there are no attributes, // which results in prepForXml returning undefined, which causes // the formatter to throw an error if that is the only object it @@ -31,7 +32,12 @@ describe("TableProperties", () => { describe("#setWidth", () => { it("should add a table width property", () => { - const tp = new TableProperties().setWidth(1234, WidthType.DXA); + const tp = new TableProperties({ + width: { + size: 1234, + type: WidthType.DXA, + }, + }); const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [{ "w:tblW": { _attr: { "w:type": "dxa", "w:w": 1234 } } }], @@ -39,7 +45,12 @@ describe("TableProperties", () => { }); it("should add a table width property with default of AUTO", () => { - const tp = new TableProperties().setWidth(1234); + const tp = new TableProperties({ + width: { + size: 1234, + }, + }); + const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [{ "w:tblW": { _attr: { "w:type": "auto", "w:w": 1234 } } }], @@ -49,8 +60,10 @@ describe("TableProperties", () => { describe("#setLayout", () => { it("sets the table to fixed width layout", () => { - const tp = new TableProperties(); - tp.setLayout(TableLayoutType.FIXED); + const tp = new TableProperties({ + layout: TableLayoutType.FIXED, + }); + const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [{ "w:tblLayout": { _attr: { "w:type": "fixed" } } }], @@ -60,8 +73,15 @@ describe("TableProperties", () => { describe("#cellMargin", () => { it("adds a table cell top margin", () => { - const tp = new TableProperties(); - tp.CellMargin.addTopMargin(1234, WidthType.DXA); + const tp = new TableProperties({ + cellMargin: { + top: { + value: 1234, + type: WidthType.DXA, + }, + }, + }); + const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [{ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }], @@ -69,8 +89,15 @@ describe("TableProperties", () => { }); it("adds a table cell left margin", () => { - const tp = new TableProperties(); - tp.CellMargin.addLeftMargin(1234, WidthType.DXA); + const tp = new TableProperties({ + cellMargin: { + left: { + value: 1234, + type: WidthType.DXA, + }, + }, + }); + const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [{ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }], @@ -80,12 +107,14 @@ describe("TableProperties", () => { describe("#setShading", () => { it("sets the shading of the table", () => { - const tp = new TableProperties(); - tp.setShading({ - fill: "b79c2f", - val: ShadingType.REVERSE_DIAGONAL_STRIPE, - color: "auto", + const tp = new TableProperties({ + shading: { + fill: "b79c2f", + val: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "auto", + }, }); + const tree = new Formatter().format(tp); expect(tree).to.deep.equal({ "w:tblPr": [ @@ -102,4 +131,40 @@ describe("TableProperties", () => { }); }); }); + + describe("#setAlignment", () => { + it("sets the alignment of the table", () => { + const tp = new TableProperties({ + alignment: AlignmentType.CENTER, + }); + const tree = new Formatter().format(tp); + expect(tree).to.deep.equal({ + "w:tblPr": [ + { + "w:jc": { + _attr: { + "w:val": "center", + }, + }, + }, + ], + }); + }); + }); + + describe("#Set Virtual Right to Left", () => { + it("sets the alignment of the table", () => { + const tp = new TableProperties({ + visuallyRightToLeft: true, + }); + const tree = new Formatter().format(tp); + expect(tree).to.deep.equal({ + "w:tblPr": [ + { + "w:bidiVisual": {}, + }, + ], + }); + }); + }); }); diff --git a/src/file/table/table-properties/table-properties.ts b/src/file/table/table-properties/table-properties.ts index 245a56c444..67fa8e3f5f 100644 --- a/src/file/table/table-properties/table-properties.ts +++ b/src/file/table/table-properties/table-properties.ts @@ -1,55 +1,68 @@ +// http://officeopenxml.com/WPtableProperties.php import { IgnoreIfEmptyXmlComponent } from "file/xml-components"; +import { Alignment, AlignmentType } from "../../paragraph"; import { ITableShadingAttributesProperties, TableShading } from "../shading"; import { WidthType } from "../table-cell"; -import { TableBorders } from "./table-borders"; -import { TableCellMargin } from "./table-cell-margin"; +import { ITableBordersOptions, TableBorders } from "./table-borders"; +import { ITableCellMarginOptions, TableCellMargin } from "./table-cell-margin"; import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties"; import { TableLayout, TableLayoutType } from "./table-layout"; import { TableStyle } from "./table-style"; import { PreferredTableWidth } from "./table-width"; +import { VisuallyRightToLeft } from "./visually-right-to-left"; + +export interface ITablePropertiesOptions { + readonly width?: { + readonly size: number; + readonly type?: WidthType; + }; + readonly layout?: TableLayoutType; + readonly borders?: ITableBordersOptions; + readonly float?: ITableFloatOptions; + readonly shading?: ITableShadingAttributesProperties; + readonly style?: string; + readonly alignment?: AlignmentType; + readonly cellMargin?: ITableCellMarginOptions; + readonly visuallyRightToLeft?: boolean; +} export class TableProperties extends IgnoreIfEmptyXmlComponent { - private readonly cellMargin: TableCellMargin; - - constructor() { + constructor(options: ITablePropertiesOptions) { super("w:tblPr"); - this.cellMargin = new TableCellMargin(); - this.root.push(this.cellMargin); - } + this.root.push(new TableCellMargin(options.cellMargin || {})); - public setWidth(width: number, type: WidthType = WidthType.AUTO): TableProperties { - this.root.push(new PreferredTableWidth(type, width)); - return this; - } + if (options.borders) { + this.root.push(new TableBorders(options.borders)); + } - public setLayout(type: TableLayoutType): void { - this.root.push(new TableLayout(type)); - } + if (options.width) { + this.root.push(new PreferredTableWidth(options.width.type, options.width.size)); + } - public setBorder(): TableProperties { - this.root.push(new TableBorders()); - return this; - } + if (options.float) { + this.root.push(new TableFloatProperties(options.float)); + } - public get CellMargin(): TableCellMargin { - return this.cellMargin; - } + if (options.layout) { + this.root.push(new TableLayout(options.layout)); + } - public setTableFloatProperties(tableFloatOptions: ITableFloatOptions): TableProperties { - this.root.push(new TableFloatProperties(tableFloatOptions)); - return this; - } + if (options.alignment) { + this.root.push(new Alignment(options.alignment)); + } - public setShading(attrs: ITableShadingAttributesProperties): TableProperties { - this.root.push(new TableShading(attrs)); + if (options.shading) { + this.root.push(new TableShading(options.shading)); + } - return this; - } + if (options.visuallyRightToLeft) { + this.root.push(new VisuallyRightToLeft()); + } - public setStyle(styleId: string): TableProperties { - this.root.push(new TableStyle(styleId)); - return this; + if (options.style) { + this.root.push(new TableStyle(options.style)); + } } } diff --git a/src/file/table/table-properties/table-width.ts b/src/file/table/table-properties/table-width.ts index a463e958df..44468c744d 100644 --- a/src/file/table/table-properties/table-width.ts +++ b/src/file/table/table-properties/table-width.ts @@ -13,7 +13,7 @@ class TableWidthAttributes extends XmlAttributeComponent { } export class PreferredTableWidth extends XmlComponent { - constructor(type: WidthType, w: number) { + constructor(type: WidthType = WidthType.AUTO, w: number) { super("w:tblW"); const width: number | string = type === WidthType.PERCENTAGE ? `${w}%` : w; this.root.push(new TableWidthAttributes({ type: type, w: width })); diff --git a/src/file/table/table-properties/visually-right-to-left.spec.ts b/src/file/table/table-properties/visually-right-to-left.spec.ts new file mode 100644 index 0000000000..792c90194b --- /dev/null +++ b/src/file/table/table-properties/visually-right-to-left.spec.ts @@ -0,0 +1,14 @@ +import { expect } from "chai"; + +import { Formatter } from "export/formatter"; +import { VisuallyRightToLeft } from "./visually-right-to-left"; + +describe("VisuallyRightToLeft", () => { + it("should create", () => { + const visuallyRightToLeft = new VisuallyRightToLeft(); + const tree = new Formatter().format(visuallyRightToLeft); + expect(tree).to.deep.equal({ + "w:bidiVisual": {}, + }); + }); +}); diff --git a/src/file/table/table-properties/visually-right-to-left.ts b/src/file/table/table-properties/visually-right-to-left.ts new file mode 100644 index 0000000000..c0598a5a26 --- /dev/null +++ b/src/file/table/table-properties/visually-right-to-left.ts @@ -0,0 +1,8 @@ +// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_bidiVisual_topic_ID0EOXIQ.html +import { XmlComponent } from "file/xml-components"; + +export class VisuallyRightToLeft extends XmlComponent { + constructor() { + super("w:bidiVisual"); + } +} diff --git a/src/file/table/table-row/table-row-height.ts b/src/file/table/table-row/table-row-height.ts index 71e2c36aa1..79e4266201 100644 --- a/src/file/table/table-row/table-row-height.ts +++ b/src/file/table/table-row/table-row-height.ts @@ -10,12 +10,12 @@ export enum HeightRule { } interface ITableRowHeight { - readonly height: number; + readonly value: number; readonly rule: HeightRule; } export class TableRowHeightAttributes extends XmlAttributeComponent { - protected readonly xmlKeys = { height: "w:val", rule: "w:hRule" }; + protected readonly xmlKeys = { value: "w:val", rule: "w:hRule" }; } export class TableRowHeight extends XmlComponent { @@ -24,7 +24,7 @@ export class TableRowHeight extends XmlComponent { this.root.push( new TableRowHeightAttributes({ - height: value, + value: value, rule: rule, }), ); diff --git a/src/file/table/table-row/table-row-properties.ts b/src/file/table/table-row/table-row-properties.ts index c9b60c13f4..1b4c9784cd 100644 --- a/src/file/table/table-row/table-row-properties.ts +++ b/src/file/table/table-row/table-row-properties.ts @@ -1,6 +1,8 @@ -import { HeightRule, TableRowHeight } from "file/table/table-row/table-row-height"; +// http://officeopenxml.com/WPtableRowProperties.php import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent, XmlComponent } from "file/xml-components"; +import { HeightRule, TableRowHeight } from "./table-row-height"; + export class TableRowProperties extends IgnoreIfEmptyXmlComponent { constructor() { super("w:trPr"); @@ -18,8 +20,8 @@ export class TableRowProperties extends IgnoreIfEmptyXmlComponent { return this; } - public setHeight(height: number, rule: HeightRule): TableRowProperties { - this.root.push(new TableRowHeight(height, rule)); + public setHeight(value: number, rule: HeightRule): TableRowProperties { + this.root.push(new TableRowHeight(value, rule)); return this; } diff --git a/src/file/table/table-row/table-row.spec.ts b/src/file/table/table-row/table-row.spec.ts index e013153cd8..16a08e10ae 100644 --- a/src/file/table/table-row/table-row.spec.ts +++ b/src/file/table/table-row/table-row.spec.ts @@ -92,7 +92,7 @@ describe("TableRow", () => { const tableRow = new TableRow({ children: [], height: { - height: 100, + value: 100, rule: HeightRule.EXACT, }, }); @@ -182,4 +182,97 @@ describe("TableRow", () => { }); }); }); + + describe("#rootIndexToColumnIndex", () => { + it("should get the correct virtual column index by root index", () => { + const tableRow = new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + ], + }); + + expect(tableRow.rootIndexToColumnIndex(1)).to.equal(0); + expect(tableRow.rootIndexToColumnIndex(2)).to.equal(3); + expect(tableRow.rootIndexToColumnIndex(3)).to.equal(4); + expect(tableRow.rootIndexToColumnIndex(4)).to.equal(5); + + expect(() => tableRow.rootIndexToColumnIndex(0)).to.throw(`cell 'rootIndex' should between 1 to 4`); + expect(() => tableRow.rootIndexToColumnIndex(5)).to.throw(`cell 'rootIndex' should between 1 to 4`); + }); + }); + + describe("#columnIndexToRootIndex", () => { + it("should get the correct root index by virtual column index", () => { + const tableRow = new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + ], + }); + + expect(tableRow.columnIndexToRootIndex(0)).to.equal(1); + expect(tableRow.columnIndexToRootIndex(1)).to.equal(1); + expect(tableRow.columnIndexToRootIndex(2)).to.equal(1); + + expect(tableRow.columnIndexToRootIndex(3)).to.equal(2); + expect(tableRow.columnIndexToRootIndex(4)).to.equal(3); + + expect(tableRow.columnIndexToRootIndex(5)).to.equal(4); + expect(tableRow.columnIndexToRootIndex(6)).to.equal(4); + expect(tableRow.columnIndexToRootIndex(7)).to.equal(4); + + expect(() => tableRow.columnIndexToRootIndex(-1)).to.throw(`cell 'columnIndex' should not less than zero`); + expect(() => tableRow.columnIndexToRootIndex(8)).to.throw(`cell 'columnIndex' should not great than 7`); + }); + + it("should allow end new cell index", () => { + const tableRow = new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + }), + new TableCell({ + children: [new Paragraph("test")], + columnSpan: 3, + }), + ], + }); + + expect(tableRow.columnIndexToRootIndex(8, true)).to.equal(5); + // for column 10, just place the new cell at the end of row + expect(tableRow.columnIndexToRootIndex(10, true)).to.equal(5); + }); + }); }); diff --git a/src/file/table/table-row/table-row.ts b/src/file/table/table-row/table-row.ts index 466b7eb320..92a8614511 100644 --- a/src/file/table/table-row/table-row.ts +++ b/src/file/table/table-row/table-row.ts @@ -7,7 +7,7 @@ export interface ITableRowOptions { readonly cantSplit?: boolean; readonly tableHeader?: boolean; readonly height?: { - readonly height: number; + readonly value: number; readonly rule: HeightRule; }; readonly children: TableCell[]; @@ -34,7 +34,7 @@ export class TableRow extends XmlComponent { } if (options.height) { - this.properties.setHeight(options.height.height, options.height.rule); + this.properties.setHeight(options.height.value, options.height.rule); } } @@ -42,12 +42,56 @@ export class TableRow extends XmlComponent { return this.options.children.length; } - public get Children(): TableCell[] { - return this.options.children; + public get cells(): TableCell[] { + return this.root.filter((xmlComponent) => xmlComponent instanceof TableCell); } public addCellToIndex(cell: TableCell, index: number): void { // Offset because properties is also in root. this.root.splice(index + 1, 0, cell); } + + public addCellToColumnIndex(cell: TableCell, columnIndex: number): void { + const rootIndex = this.columnIndexToRootIndex(columnIndex, true); + this.addCellToIndex(cell, rootIndex - 1); + } + + public rootIndexToColumnIndex(rootIndex: number): number { + // convert the root index to the virtual column index + if (rootIndex < 1 || rootIndex >= this.root.length) { + throw new Error(`cell 'rootIndex' should between 1 to ${this.root.length - 1}`); + } + let colIdx = 0; + // Offset because properties is also in root. + for (let rootIdx = 1; rootIdx < rootIndex; rootIdx++) { + const cell = this.root[rootIdx] as TableCell; + colIdx += cell.options.columnSpan || 1; + } + return colIdx; + } + + public columnIndexToRootIndex(columnIndex: number, allowEndNewCell: boolean = false): number { + // convert the virtual column index to the root index + // `allowEndNewCell` for get index to inert new cell + if (columnIndex < 0) { + throw new Error(`cell 'columnIndex' should not less than zero`); + } + let colIdx = 0; + // Offset because properties is also in root. + let rootIdx = 1; + while (colIdx <= columnIndex) { + if (rootIdx >= this.root.length) { + if (allowEndNewCell) { + // for inserting verticalMerge CONTINUE cell at end of row + return this.root.length; + } else { + throw new Error(`cell 'columnIndex' should not great than ${colIdx - 1}`); + } + } + const cell = this.root[rootIdx] as TableCell; + rootIdx += 1; + colIdx += (cell && cell.options.columnSpan) || 1; + } + return rootIdx - 1; + } } diff --git a/src/file/table/table.spec.ts b/src/file/table/table.spec.ts index d2aec26051..3165330047 100644 --- a/src/file/table/table.spec.ts +++ b/src/file/table/table.spec.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { Paragraph } from "../paragraph"; +import { AlignmentType, Paragraph } from "../paragraph"; import { Table } from "./table"; // import { WidthType } from "./table-cell"; import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties"; @@ -188,6 +188,72 @@ describe("Table", () => { }); }); + it("creates a table with the correct columnSpan and rowSpan", () => { + const table = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + rowSpan: 2, + }), + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], + }); + const tree = new Formatter().format(table); + const cellP = { "w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "hello"] }] }] }; + expect(tree).to.deep.equal({ + "w:tbl": [ + { "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] }, + { + "w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }], + }, + { + "w:tr": [ + { + "w:tc": [{ "w:tcPr": [{ "w:gridSpan": { _attr: { "w:val": 2 } } }] }, cellP], + }, + ], + }, + { + "w:tr": [ + { + "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, cellP], + }, + { "w:tc": [cellP] }, + ], + }, + { + "w:tr": [ + { + "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": {} }], + }, + { "w:tc": [cellP] }, + ], + }, + ], + }); + }); + it("sets the table to fixed width layout", () => { const table = new Table({ rows: [ @@ -202,15 +268,32 @@ describe("Table", () => { layout: TableLayoutType.FIXED, }); const tree = new Formatter().format(table); - expect(tree) - .to.have.property("w:tbl") - .which.is.an("array") - .with.has.length.at.least(1); + expect(tree).to.have.property("w:tbl").which.is.an("array").with.has.length.at.least(1); expect(tree["w:tbl"][0]).to.deep.equal({ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS, { "w:tblLayout": { _attr: { "w:type": "fixed" } } }], }); }); + it("should center the table", () => { + const table = new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], + alignment: AlignmentType.CENTER, + }); + const tree = new Formatter().format(table); + expect(tree).to.have.property("w:tbl").which.is.an("array").with.has.length.at.least(1); + expect(tree["w:tbl"][0]).to.deep.equal({ + "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS, { "w:jc": { _attr: { "w:val": "center" } } }], + }); + }); + it("should set the table to provided width", () => { const table = new Table({ rows: [ @@ -229,10 +312,7 @@ describe("Table", () => { layout: TableLayoutType.FIXED, }); const tree = new Formatter().format(table); - expect(tree) - .to.have.property("w:tbl") - .which.is.an("array") - .with.has.length.at.least(1); + expect(tree).to.have.property("w:tbl").which.is.an("array").with.has.length.at.least(1); expect(tree["w:tbl"][0]).to.deep.equal({ "w:tblPr": [ DEFAULT_TABLE_PROPERTIES, @@ -266,14 +346,10 @@ describe("Table", () => { ], }); const tree = new Formatter().format(table); - expect(tree) - .to.have.property("w:tbl") - .which.is.an("array"); + expect(tree).to.have.property("w:tbl").which.is.an("array"); const row = tree["w:tbl"].find((x) => x["w:tr"]); expect(row).not.to.be.undefined; - expect(row["w:tr"]) - .to.be.an("array") - .which.has.length.at.least(1); + expect(row["w:tr"]).to.be.an("array").which.has.length.at.least(1); expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({ "w:tc": [ { @@ -398,10 +474,7 @@ describe("Table", () => { }, }); const tree = new Formatter().format(table); - expect(tree) - .to.have.property("w:tbl") - .which.is.an("array") - .with.has.length.at.least(1); + expect(tree).to.have.property("w:tbl").which.is.an("array").with.has.length.at.least(1); expect(tree["w:tbl"][0]).to.deep.equal({ "w:tblPr": [ DEFAULT_TABLE_PROPERTIES, diff --git a/src/file/table/table.ts b/src/file/table/table.ts index 1a7b7d6549..ea4acd93d5 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -1,8 +1,10 @@ // http://officeopenxml.com/WPtableGrid.php import { XmlComponent } from "file/xml-components"; + +import { AlignmentType } from "../paragraph"; import { TableGrid } from "./grid"; import { TableCell, VerticalMergeType, WidthType } from "./table-cell"; -import { ITableFloatOptions, TableProperties } from "./table-properties"; +import { ITableBordersOptions, ITableFloatOptions, TableProperties } from "./table-properties"; import { TableLayoutType } from "./table-properties/table-layout"; import { TableRow } from "./table-row"; @@ -33,11 +35,12 @@ export interface ITableOptions { readonly float?: ITableFloatOptions; readonly layout?: TableLayoutType; readonly style?: string; + readonly borders?: ITableBordersOptions; + readonly alignment?: AlignmentType; + readonly visuallyRightToLeft?: boolean; } export class Table extends XmlComponent { - private readonly properties: TableProperties; - constructor({ rows, width, @@ -46,26 +49,41 @@ export class Table extends XmlComponent { float, layout, style, + borders, + alignment, + visuallyRightToLeft, }: ITableOptions) { super("w:tbl"); - this.properties = new TableProperties(); - this.root.push(this.properties); - this.properties.setBorder(); - if (style) { - this.properties.setStyle(style); - } - - if (width) { - this.properties.setWidth(width.size, width.type); - } else { - this.properties.setWidth(100); - } - - this.properties.CellMargin.addBottomMargin(bottom || 0, marginUnitType); - this.properties.CellMargin.addTopMargin(top || 0, marginUnitType); - this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType); - this.properties.CellMargin.addRightMargin(right || 0, marginUnitType); + this.root.push( + new TableProperties({ + borders: borders ?? {}, + width: width ?? { size: 100 }, + float, + layout, + style, + alignment, + cellMargin: { + bottom: { + value: bottom || 0, + type: marginUnitType, + }, + top: { + value: top || 0, + type: marginUnitType, + }, + left: { + value: left || 0, + type: marginUnitType, + }, + right: { + value: right || 0, + type: marginUnitType, + }, + }, + visuallyRightToLeft, + }), + ); this.root.push(new TableGrid(columnWidths)); @@ -73,34 +91,28 @@ export class Table extends XmlComponent { this.root.push(row); } - for (const row of rows) { - row.Children.forEach((cell, cellIndex) => { - const column = rows.map((r) => r.Children[cellIndex]); + rows.forEach((row, rowIndex) => { + if (rowIndex === rows.length - 1) { + // don't process the end row + return; + } + let columnIndex = 0; + row.cells.forEach((cell) => { // Row Span has to be added in this method and not the constructor because it needs to know information about the column which happens after Table Cell construction // Row Span of 1 will crash word as it will add RESTART and not a corresponding CONTINUE if (cell.options.rowSpan && cell.options.rowSpan > 1) { - const thisCellsColumnIndex = column.indexOf(cell); - const endColumnIndex = thisCellsColumnIndex + (cell.options.rowSpan - 1); - - for (let i = thisCellsColumnIndex + 1; i <= endColumnIndex; i++) { - rows[i].addCellToIndex( - new TableCell({ - children: [], - verticalMerge: VerticalMergeType.CONTINUE, - }), - i, - ); - } + const continueCell = new TableCell({ + // the inserted CONTINUE cell has rowSpan, and will be handled when process the next row + rowSpan: cell.options.rowSpan - 1, + columnSpan: cell.options.columnSpan, + borders: cell.options.borders, + children: [], + verticalMerge: VerticalMergeType.CONTINUE, + }); + rows[rowIndex + 1].addCellToColumnIndex(continueCell, columnIndex); } + columnIndex += cell.options.columnSpan || 1; }); - } - - if (float) { - this.properties.setTableFloatProperties(float); - } - - if (layout) { - this.properties.setLayout(layout); - } + }); } } diff --git a/src/file/track-revision/index.ts b/src/file/track-revision/index.ts new file mode 100644 index 0000000000..eb2465d8fe --- /dev/null +++ b/src/file/track-revision/index.ts @@ -0,0 +1,2 @@ +export * from "./track-revision-components/inserted-text-run"; +export * from "./track-revision-components/deleted-text-run"; diff --git a/src/file/track-revision/track-revision-components/deleted-page-number.spec.ts b/src/file/track-revision/track-revision-components/deleted-page-number.spec.ts new file mode 100644 index 0000000000..5e0238da96 --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-page-number.spec.ts @@ -0,0 +1,30 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { DeletedNumberOfPages, DeletedNumberOfPagesSection, DeletedPage } from "./deleted-page-number"; + +describe("Deleted Page", () => { + describe("#constructor()", () => { + it("uses the font name for both ascii and hAnsi", () => { + const tree = new Formatter().format(new DeletedPage()); + expect(tree).to.deep.equal({ "w:delInstrText": [{ _attr: { "xml:space": "preserve" } }, "PAGE"] }); + }); + }); +}); + +describe("Delted NumberOfPages", () => { + describe("#constructor()", () => { + it("uses the font name for both ascii and hAnsi", () => { + const tree = new Formatter().format(new DeletedNumberOfPages()); + expect(tree).to.deep.equal({ "w:delInstrText": [{ _attr: { "xml:space": "preserve" } }, "NUMPAGES"] }); + }); + }); +}); + +describe("Deleted NumberOfPagesSection", () => { + describe("#constructor()", () => { + it("uses the font name for both ascii and hAnsi", () => { + const tree = new Formatter().format(new DeletedNumberOfPagesSection()); + expect(tree).to.deep.equal({ "w:delInstrText": [{ _attr: { "xml:space": "preserve" } }, "SECTIONPAGES"] }); + }); + }); +}); diff --git a/src/file/track-revision/track-revision-components/deleted-page-number.ts b/src/file/track-revision/track-revision-components/deleted-page-number.ts new file mode 100644 index 0000000000..6ce6266f13 --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-page-number.ts @@ -0,0 +1,30 @@ +import { SpaceType } from "file/space-type"; +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class TextAttributes extends XmlAttributeComponent<{ readonly space: SpaceType }> { + protected readonly xmlKeys = { space: "xml:space" }; +} + +export class DeletedPage extends XmlComponent { + constructor() { + super("w:delInstrText"); + this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); + this.root.push("PAGE"); + } +} + +export class DeletedNumberOfPages extends XmlComponent { + constructor() { + super("w:delInstrText"); + this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); + this.root.push("NUMPAGES"); + } +} + +export class DeletedNumberOfPagesSection extends XmlComponent { + constructor() { + super("w:delInstrText"); + this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); + this.root.push("SECTIONPAGES"); + } +} diff --git a/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts b/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts new file mode 100644 index 0000000000..6bd11c24d7 --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts @@ -0,0 +1,372 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { FootnoteReferenceRun, PageNumber } from "../../index"; +import { DeletedTextRun } from "./deleted-text-run"; + +describe("DeletedTextRun", () => { + describe("#constructor", () => { + it("should create a deleted text run", () => { + const deletedTextRun = new DeletedTextRun({ text: "some text", id: 0, date: "123", author: "Author" }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "some text", + ], + }, + ], + }, + ], + }); + }); + }); + + describe("#constructor with formatting", () => { + it("should create a deleted text run", () => { + const deletedTextRun = new DeletedTextRun({ text: "some text", bold: true, id: 0, date: "123", author: "Author" }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:rPr": [ + { + "w:b": { + _attr: { + "w:val": true, + }, + }, + }, + { + "w:bCs": { + _attr: { + "w:val": true, + }, + }, + }, + ], + }, + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "some text", + ], + }, + ], + }, + ], + }); + }); + }); + + describe("#break()", () => { + it("should add a break", () => { + const deletedTextRun = new DeletedTextRun({ + break: 1, + children: ["some text"], + id: 0, + date: "123", + author: "Author", + }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:br": {}, + }, + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "some text", + ], + }, + ], + }, + ], + }); + }); + }); + + describe("page numbering", () => { + it("should be able to delete the total pages", () => { + const deletedTextRun = new DeletedTextRun({ + children: [" to ", PageNumber.TOTAL_PAGES], + id: 0, + date: "123", + author: "Author", + }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + " to ", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "begin", + }, + }, + }, + { + "w:delInstrText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "NUMPAGES", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "separate", + }, + }, + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "end", + }, + }, + }, + ], + }, + ], + }); + }); + + it("should be able to delete the total pages in section", () => { + const deletedTextRun = new DeletedTextRun({ + children: [" to ", PageNumber.TOTAL_PAGES_IN_SECTION], + id: 0, + date: "123", + author: "Author", + }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + " to ", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "begin", + }, + }, + }, + { + "w:delInstrText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "SECTIONPAGES", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "separate", + }, + }, + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "end", + }, + }, + }, + ], + }, + ], + }); + }); + + it("should be able to delete the current page", () => { + const deletedTextRun = new DeletedTextRun({ + children: [" to ", PageNumber.CURRENT], + id: 0, + date: "123", + author: "Author", + }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + " to ", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "begin", + }, + }, + }, + { + "w:delInstrText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "PAGE", + ], + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "separate", + }, + }, + }, + { + "w:fldChar": { + _attr: { + "w:fldCharType": "end", + }, + }, + }, + ], + }, + ], + }); + }); + }); + + describe("footnote references", () => { + it("should add a valid footnote reference", () => { + const deletedTextRun = new DeletedTextRun({ + children: ["some text", new FootnoteReferenceRun(1)], + id: 0, + date: "123", + author: "Author", + }); + const tree = new Formatter().format(deletedTextRun); + expect(tree).to.deep.equal({ + "w:del": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:delText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "some text", + ], + }, + { + "w:r": [ + { "w:rPr": [{ "w:rStyle": { _attr: { "w:val": "FootnoteReference" } } }] }, + { "w:footnoteReference": { _attr: { "w:id": 1 } } }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/track-revision/track-revision-components/deleted-text-run.ts b/src/file/track-revision/track-revision-components/deleted-text-run.ts new file mode 100644 index 0000000000..7830d3d63c --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-text-run.ts @@ -0,0 +1,76 @@ +import { XmlComponent } from "file/xml-components"; + +import { IRunOptions, RunProperties } from "../../index"; +import { Break } from "../../paragraph/run/break"; +import { Begin, End, Separate } from "../../paragraph/run/field"; +import { PageNumber } from "../../paragraph/run/run"; +import { ChangeAttributes, IChangedAttributesProperties } from "../track-revision"; +import { DeletedNumberOfPages, DeletedNumberOfPagesSection, DeletedPage } from "./deleted-page-number"; +import { DeletedText } from "./deleted-text"; + +interface IDeletedRunOptions extends IRunOptions, IChangedAttributesProperties {} + +export class DeletedTextRun extends XmlComponent { + protected readonly deletedTextRunWrapper: DeletedTextRunWrapper; + + constructor(options: IDeletedRunOptions) { + super("w:del"); + this.root.push( + new ChangeAttributes({ + id: options.id, + author: options.author, + date: options.date, + }), + ); + this.deletedTextRunWrapper = new DeletedTextRunWrapper(options); + this.addChildElement(this.deletedTextRunWrapper); + } +} + +class DeletedTextRunWrapper extends XmlComponent { + constructor(options: IRunOptions) { + super("w:r"); + this.root.push(new RunProperties(options)); + + if (options.children) { + for (const child of options.children) { + if (typeof child === "string") { + switch (child) { + case PageNumber.CURRENT: + this.root.push(new Begin()); + this.root.push(new DeletedPage()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + case PageNumber.TOTAL_PAGES: + this.root.push(new Begin()); + this.root.push(new DeletedNumberOfPages()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + case PageNumber.TOTAL_PAGES_IN_SECTION: + this.root.push(new Begin()); + this.root.push(new DeletedNumberOfPagesSection()); + this.root.push(new Separate()); + this.root.push(new End()); + break; + default: + this.root.push(new DeletedText(child)); + break; + } + continue; + } + + this.root.push(child); + } + } else if (options.text) { + this.root.push(new DeletedText(options.text)); + } + + if (options.break) { + for (let i = 0; i < options.break; i++) { + this.root.splice(1, 0, new Break()); + } + } + } +} diff --git a/src/file/track-revision/track-revision-components/deleted-text.spec.ts b/src/file/track-revision/track-revision-components/deleted-text.spec.ts new file mode 100644 index 0000000000..d9c8de46bf --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-text.spec.ts @@ -0,0 +1,15 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { DeletedText } from "./deleted-text"; + +describe("Deleted Text", () => { + describe("#constructor", () => { + it("adds the passed in text to the component", () => { + const t = new DeletedText(" this is\n text"); + const f = new Formatter().format(t); + expect(f).to.deep.equal({ + "w:delText": [{ _attr: { "xml:space": "preserve" } }, " this is\n text"], + }); + }); + }); +}); diff --git a/src/file/track-revision/track-revision-components/deleted-text.ts b/src/file/track-revision/track-revision-components/deleted-text.ts new file mode 100644 index 0000000000..408b47304d --- /dev/null +++ b/src/file/track-revision/track-revision-components/deleted-text.ts @@ -0,0 +1,15 @@ +import { SpaceType } from "file/space-type"; +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class TextAttributes extends XmlAttributeComponent<{ readonly space: SpaceType }> { + protected readonly xmlKeys = { space: "xml:space" }; +} + +export class DeletedText extends XmlComponent { + constructor(text: string) { + super("w:delText"); + this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); + + this.root.push(text); + } +} diff --git a/src/file/track-revision/track-revision-components/inserted-text-run.spec.ts b/src/file/track-revision/track-revision-components/inserted-text-run.spec.ts new file mode 100644 index 0000000000..c23069fbba --- /dev/null +++ b/src/file/track-revision/track-revision-components/inserted-text-run.spec.ts @@ -0,0 +1,37 @@ +import { expect } from "chai"; +import { Formatter } from "export/formatter"; +import { InsertedTextRun } from "./inserted-text-run"; + +describe("InsertedTextRun", () => { + describe("#constructor", () => { + it("should create a inserted text run", () => { + const insertedTextRun = new InsertedTextRun({ text: "some text", id: 0, date: "123", author: "Author" }); + const tree = new Formatter().format(insertedTextRun); + expect(tree).to.deep.equal({ + "w:ins": [ + { + _attr: { + "w:author": "Author", + "w:date": "123", + "w:id": 0, + }, + }, + { + "w:r": [ + { + "w:t": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "some text", + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/track-revision/track-revision-components/inserted-text-run.ts b/src/file/track-revision/track-revision-components/inserted-text-run.ts new file mode 100644 index 0000000000..3d39e92c1c --- /dev/null +++ b/src/file/track-revision/track-revision-components/inserted-text-run.ts @@ -0,0 +1,20 @@ +import { XmlComponent } from "file/xml-components"; + +import { IRunOptions, TextRun } from "../../index"; +import { ChangeAttributes, IChangedAttributesProperties } from "../track-revision"; + +interface IInsertedRunOptions extends IChangedAttributesProperties, IRunOptions {} + +export class InsertedTextRun extends XmlComponent { + constructor(options: IInsertedRunOptions) { + super("w:ins"); + this.root.push( + new ChangeAttributes({ + id: options.id, + author: options.author, + date: options.date, + }), + ); + this.addChildElement(new TextRun(options as IRunOptions)); + } +} diff --git a/src/file/track-revision/track-revision.ts b/src/file/track-revision/track-revision.ts new file mode 100644 index 0000000000..4318e9a468 --- /dev/null +++ b/src/file/track-revision/track-revision.ts @@ -0,0 +1,15 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IChangedAttributesProperties { + readonly id: number; + readonly author: string; + readonly date: string; +} + +export class ChangeAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { + id: "w:id", + author: "w:author", + date: "w:date", + }; +} diff --git a/src/file/xml-components/base.ts b/src/file/xml-components/base.ts index cfc4ec47b3..4bb37c8ad9 100644 --- a/src/file/xml-components/base.ts +++ b/src/file/xml-components/base.ts @@ -1,3 +1,4 @@ +import { IViewWrapper } from "../document-wrapper"; import { IXmlableObject } from "./xmlable-object"; export abstract class BaseXmlComponent { @@ -9,7 +10,7 @@ export abstract class BaseXmlComponent { this.rootKey = rootKey; } - public abstract prepForXml(): IXmlableObject | undefined; + public abstract prepForXml(file?: IViewWrapper): IXmlableObject | undefined; public get IsDeleted(): boolean { return this.deleted; diff --git a/src/file/xml-components/index.ts b/src/file/xml-components/index.ts index 66e9641bfd..295161b395 100644 --- a/src/file/xml-components/index.ts +++ b/src/file/xml-components/index.ts @@ -4,3 +4,4 @@ export * from "./default-attributes"; export * from "./imported-xml-component"; export * from "./xmlable-object"; export * from "./initializable-xml-component"; +export * from "./base"; diff --git a/src/file/xml-components/xml-component.ts b/src/file/xml-components/xml-component.ts index 59192e3e4d..84fd5f98e4 100644 --- a/src/file/xml-components/xml-component.ts +++ b/src/file/xml-components/xml-component.ts @@ -1,19 +1,19 @@ +import { IViewWrapper } from "../document-wrapper"; import { BaseXmlComponent } from "./base"; import { IXmlableObject } from "./xmlable-object"; -export { BaseXmlComponent }; export const EMPTY_OBJECT = Object.seal({}); export abstract class XmlComponent extends BaseXmlComponent { - // tslint:disable-next-line:readonly-keyword - protected root: Array; + // tslint:disable-next-line:readonly-keyword no-any + protected root: (BaseXmlComponent | string | any)[]; constructor(rootKey: string) { super(rootKey); this.root = new Array(); } - public prepForXml(): IXmlableObject | undefined { + public prepForXml(file?: IViewWrapper): IXmlableObject | undefined { const children = this.root .filter((c) => { if (c instanceof BaseXmlComponent) { @@ -23,7 +23,7 @@ export abstract class XmlComponent extends BaseXmlComponent { }) .map((comp) => { if (comp instanceof BaseXmlComponent) { - return comp.prepForXml(); + return comp.prepForXml(file); } return comp; }) diff --git a/src/import-dotx/import-dotx.ts b/src/import-dotx/import-dotx.ts index 2b1261efe7..4c77ea75be 100644 --- a/src/import-dotx/import-dotx.ts +++ b/src/import-dotx/import-dotx.ts @@ -17,8 +17,8 @@ const schemeToType = { }; interface IDocumentRefs { - readonly headers: Array<{ readonly id: number; readonly type: HeaderReferenceType }>; - readonly footers: Array<{ readonly id: number; readonly type: FooterReferenceType }>; + readonly headers: { readonly id: number; readonly type: HeaderReferenceType }[]; + readonly footers: { readonly id: number; readonly type: FooterReferenceType }[]; } enum RelationshipType { @@ -46,7 +46,9 @@ export interface IDocumentTemplate { } export class ImportDotx { - public async extract(data: Buffer): Promise { + public async extract( + data: Buffer | string | number[] | Uint8Array | ArrayBuffer | Blob | NodeJS.ReadableStream, + ): Promise { const zipContent = await JSZip.loadAsync(data); const documentContent = await zipContent.files["word/document.xml"].async("text"); @@ -99,7 +101,7 @@ export class ImportDotx { return { type: reference.type, footer: wrapper }; }) - .filter((x) => !!x) as Array>; + .filter((x) => !!x) as Promise[]; return Promise.all(result); } @@ -134,7 +136,7 @@ export class ImportDotx { return { type: reference.type, header: wrapper }; }) - .filter((x) => !!x) as Array>; + .filter((x) => !!x) as Promise[]; return Promise.all(result); } diff --git a/src/index.ts b/src/index.ts index 1e35c87d30..a319e4dcfe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export { File as Document } from "./file"; export * from "./file"; export * from "./export"; export * from "./import-dotx"; +export * from "./convenience-functions"; diff --git a/tslint.json b/tslint.json index d6eb606eba..cb979f920a 100644 --- a/tslint.json +++ b/tslint.json @@ -21,6 +21,8 @@ "no-duplicate-imports": true, "unnecessary-constructor": true, "file-name-casing": [true, "kebab-case"], + "interface-name": [true, "always-prefix"], + "ordered-imports": true, // Functional Programming Rules "no-parameter-reassignment": true, "readonly-keyword": true, diff --git a/webpack.config.ts b/webpack.config.ts index ac1bbbb7b3..6471647d2f 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -9,6 +9,7 @@ module.exports = { path: path.resolve("build"), filename: "index.js", libraryTarget: "umd", + library: "docx", }, resolve: { @@ -24,15 +25,16 @@ module.exports = { }, // For coverage testing ...(process.env.NODE_ENV !== "production" - ? [{ - test: /\.(ts)/, - include: path.resolve("src"), - loader: "istanbul-instrumenter-loader", - enforce: "post", - exclude: [/node_modules/], - }] - : [] - ) + ? [ + { + test: /\.(ts)/, + include: path.resolve("src"), + loader: "istanbul-instrumenter-loader", + enforce: "post", + exclude: [/node_modules/], + }, + ] + : []), ], },