├── .babelrc ├── .circleci └── config.yml ├── .gitignore ├── .npmrc ├── LICENSE.md ├── README.md ├── codecov.yml ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── Types.ts ├── api │ ├── Internals.ts │ ├── JavaScriptExcel.ts │ ├── constants.ts │ └── xlsx.ts ├── index.ts ├── util │ ├── ExcelUtil.ts │ └── Helper.ts └── xlsx │ ├── FileContentTypes.ts │ ├── _rels │ └── DirectoryRels.ts │ ├── docProps │ ├── DirectoryDocsProps.ts │ ├── FileDocPropsApp.ts │ ├── FileDocPropsCore.ts │ └── FileDocPropsCustom.ts │ └── xl │ ├── DirectoryXl.ts │ ├── FileSharedStrings.ts │ ├── FileStyles.ts │ ├── FileWorkbook.ts │ ├── _rels │ └── DirectoryRels.ts │ ├── theme │ └── FileTheme1.ts │ └── worksheets │ └── FileWorksheet.ts ├── test └── unit │ └── Helper.test.ts └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/env", 4 | "@babel/typescript" 5 | ], 6 | "plugins": [ 7 | "@babel/proposal-class-properties", 8 | "@babel/proposal-object-rest-spread" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | aliases: 4 | - &defaults 5 | working_directory: ~/javascript-excel 6 | - &node6_executor 7 | docker: 8 | - image: circleci/node:6 9 | - &node8_executor 10 | docker: 11 | - image: circleci/node:8 12 | - &node9_executor 13 | docker: 14 | - image: circleci/node:9 15 | - &node10_executor 16 | docker: 17 | - image: circleci/node:10 18 | - &default_executor 19 | <<: *node9_executor 20 | - &repo_key 21 | repo-{{ .Branch }}-{{ .Revision }} 22 | - &coverage_key 23 | coverage-{{ .Branch }}-{{ .Revision }} 24 | - &base_config_key 25 | base-config-{{ .Branch }}-{{ .Revision }} 26 | - &restore_repo 27 | restore_cache: 28 | keys: 29 | - *repo_key 30 | - &ignore_non_dev_branches 31 | filters: 32 | tags: 33 | only: /.*/ 34 | branches: 35 | ignore: 36 | - /release\/.*/ 37 | - &execute_on_release 38 | filters: 39 | tags: 40 | only: /(v)?[0-9]+(\.[0-9]+)*/ 41 | branches: 42 | ignore: 43 | - /.*/ 44 | 45 | jobs: 46 | prepare: 47 | <<: *defaults 48 | <<: *default_executor 49 | steps: 50 | - *restore_repo 51 | - checkout 52 | - restore_cache: 53 | key: *base_config_key 54 | - run: 55 | name: Install Js dependencies 56 | command: yarn install --no-progress 57 | - run: 58 | name: Build project 59 | command: yarn run build 60 | - save_cache: 61 | key: *repo_key 62 | paths: 63 | - ~/javascript-excel 64 | 65 | test_node6: 66 | <<: *defaults 67 | <<: *node6_executor 68 | steps: 69 | - *restore_repo 70 | - run: 71 | name: Test with Node 6 72 | command: yarn run test 73 | 74 | test_node8: 75 | <<: *defaults 76 | <<: *node8_executor 77 | steps: 78 | - *restore_repo 79 | - run: 80 | name: Test with Node 8 81 | command: | 82 | yarn test 83 | 84 | test_node9: 85 | <<: *defaults 86 | <<: *default_executor 87 | steps: 88 | - *restore_repo 89 | - run: 90 | name: Test with Node 9 91 | command: | 92 | yarn test 93 | - save_cache: 94 | key: *coverage_key 95 | paths: 96 | - coverage 97 | 98 | test_node10: 99 | <<: *defaults 100 | <<: *node10_executor 101 | steps: 102 | - *restore_repo 103 | - run: 104 | name: Test with Node 10 105 | command: | 106 | yarn run test 107 | 108 | # test_size: 109 | # <<: *defaults 110 | # <<: *default_executor 111 | # steps: 112 | # - *restore_repo 113 | # - run: 114 | # name: Test size 115 | # command: yarn test:size 116 | 117 | coverage: 118 | <<: *defaults 119 | <<: *default_executor 120 | steps: 121 | - *restore_repo 122 | - restore_cache: 123 | key: *coverage_key 124 | - run: 125 | name: Publish coverage 126 | command: yarn run coverage:publish 127 | - store_artifacts: 128 | path: coverage/clover.xml 129 | prefix: tests 130 | - store_artifacts: 131 | path: coverage 132 | prefix: coverage 133 | - store_test_results: 134 | path: coverage/clover.xml 135 | 136 | workflows: 137 | version: 2 138 | workflow: 139 | jobs: 140 | - prepare: 141 | <<: *ignore_non_dev_branches 142 | - test_node6: 143 | requires: 144 | - prepare 145 | <<: *ignore_non_dev_branches 146 | - test_node8: 147 | requires: 148 | - prepare 149 | <<: *ignore_non_dev_branches 150 | - test_node9: 151 | requires: 152 | - prepare 153 | <<: *ignore_non_dev_branches 154 | - test_node10: 155 | requires: 156 | - prepare 157 | <<: *ignore_non_dev_branches 158 | - coverage: 159 | requires: 160 | - test_node6 161 | - test_node8 162 | - test_node9 163 | - test_node10 164 | <<: *ignore_non_dev_branches -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules/ 3 | lib/ 4 | lib-playground/ 5 | coverage/ 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | save-exact = true 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2018 Afzal Ahmad 📧 (securedeveloper@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript-Excel [WIP] 2 | A lightweight Excel file build API built with :heart:, powered by `JavaScript` 3 | 4 | [![npm version](https://badge.fury.io/js/javascript-excel.svg)](https://badge.fury.io/js/javascript-excel) 5 | [![dependencies Status](https://david-dm.org/securedeveloper/javascript-excel/status.svg)](https://david-dm.org/securedeveloper/javascript-excel) 6 | [![devDependencies Status](https://david-dm.org/securedeveloper/javascript-excel/dev-status.svg)](https://david-dm.org/securedeveloper/javascript-excel?type=dev) 7 | [![CircleCI](https://circleci.com/gh/securedeveloper/javascript-excel.svg?style=svg)](https://circleci.com/gh/securedeveloper/javascript-excel) 8 | [![Known Vulnerabilities](https://snyk.io/test/github/securedeveloper/javascript-excel/badge.svg?targetFile=package.json)](https://snyk.io/test/github/securedeveloper/javascript-excel?targetFile=package.json) 9 | [![codecov](https://codecov.io/gh/securedeveloper/javascript-excel/branch/master/graph/badge.svg)](https://codecov.io/gh/securedeveloper/javascript-excel) 10 | 11 | ## Installation 12 | 13 | With [npm](https://www.npmjs.org/package/javascript-excel): 14 | 15 | ```sh 16 | npm install javascript-excel --save 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | parsers: 16 | gcov: 17 | branch_detection: 18 | conditional: yes 19 | loop: yes 20 | method: no 21 | macro: no 22 | 23 | comment: 24 | layout: "header, diff" 25 | behavior: default 26 | require_changes: no 27 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "collectCoverage": true, 3 | "coverageDirectory": "./coverage/", 4 | "collectCoverageFrom": [ 5 | "**/src/util/*.{ts,tsx}", 6 | "!**/src/api/*.{ts,tsx}", 7 | "!**/src/xlsx/*.{ts,tsx}", 8 | "!**/.circleci/**", 9 | "!**/.idea/**", 10 | "!**/lib/**", 11 | "!**/node_modules/**", 12 | ], 13 | "transform": { 14 | "^.+\\.(ts|tsx)$": "ts-jest" 15 | }, 16 | "testRegex": ".*/test/(.*/)?.*.test.(ts|tsx)", 17 | "moduleFileExtensions": [ 18 | "ts", 19 | "tsx", 20 | "js" 21 | ], 22 | "moduleDirectories": [ 23 | "node_modules" 24 | ], 25 | "modulePathIgnorePatterns": [ 26 | "/.circleci", 27 | "/.idea", 28 | "/coverage", 29 | "/lib", 30 | "/node_modules", 31 | "/.gitignore", 32 | "/.npmrc", 33 | "/README.md", 34 | "/tsconfig.json" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-excel", 3 | "author": { 4 | "name": "Afzal Ahmad", 5 | "email": "securedeveloper@gmail.com", 6 | "url": "https://github.com/securedeveloper" 7 | }, 8 | "description": "A lightweight library to build excel sheet with JavaScript", 9 | "keywords": [ 10 | "js-excel", 11 | "javascript-excel", 12 | "excel", 13 | "xlsx", 14 | "js-csv", 15 | "javascript-csv", 16 | "csv" 17 | ], 18 | "version": "1.0.3", 19 | "main": "lib/index.js", 20 | "license": "MIT", 21 | "scripts": { 22 | "build": "npm run clean && npm run test && npm run build:types && npm run build:js", 23 | "build:types": "tsc --emitDeclarationOnly", 24 | "build:js": "babel src --out-dir lib --extensions \".ts,.tsx\"", 25 | "clean": "rm -rf ./lib && mkdir ./lib", 26 | "build:watch": "babel -w src --out-dir lib", 27 | "prepare": "npm run build", 28 | "test": "jest", 29 | "test:size": "bundlesize", 30 | "coverage:publish": "codecov", 31 | "type-check": "tsc --noEmit", 32 | "type-check:watch": "npm run type-check -- --watch" 33 | }, 34 | "devDependencies": { 35 | "@babel/cli": "7.0.0", 36 | "@babel/core": "7.0.0", 37 | "@babel/plugin-proposal-class-properties": "7.0.0", 38 | "@babel/plugin-proposal-object-rest-spread": "7.0.0", 39 | "@babel/preset-env": "7.0.0", 40 | "@babel/preset-typescript": "7.0.0", 41 | "@types/jest": "23.3.2", 42 | "babel-loader": "8.0.0", 43 | "bundlesize": "0.17.0", 44 | "codecov": "3.1.0", 45 | "jest": "23.6.0", 46 | "ts-jest": "23.1.4", 47 | "typescript": "3.0.3" 48 | }, 49 | "bundlesize": [ 50 | { 51 | "path": "./lib/*.js", 52 | "maxSize": "5 kB" 53 | } 54 | ], 55 | "dependencies": {}, 56 | "repository": { 57 | "type": "git", 58 | "url": "git+https://github.com/securedeveloper/javascript-excel.git" 59 | }, 60 | "bugs": { 61 | "url": "https://github.com/securedeveloper/javascript-excel/issues", 62 | "email": "securedeveloper@gmail.com" 63 | }, 64 | "homepage": "https://github.com/securedeveloper/javascript-excel#readme" 65 | } 66 | -------------------------------------------------------------------------------- /src/Types.ts: -------------------------------------------------------------------------------- 1 | // TODO: Write down the documentation for reach of the following interfaces and types 2 | 3 | interface JSETextStyle { 4 | bold?: boolean; 5 | italic?: boolean; 6 | underline?: boolean; 7 | } 8 | 9 | export interface JSEColor { 10 | rgb?: string; // in hex format without hash 11 | theme?: string; 12 | tint?: string; 13 | } 14 | 15 | export interface JSEFont extends JSETextStyle { 16 | name: string; // default Calibri 17 | size: number; //default 11 18 | color: JSEColor | string //simple hex value; 19 | family?: string; 20 | } 21 | 22 | /** 23 | * JSEFill interface 24 | * @param patternType 25 | * @child {fgColor, bgColor} 26 | */ 27 | 28 | export type JSEFillPattern = "none" | "gray125" | "solid"; 29 | 30 | export interface JSEFill { 31 | pattern?: JSEFillPattern; 32 | //childElements?: Array; 33 | } 34 | 35 | /** 36 | * JSECellBorder interface 37 | */ 38 | 39 | export type JSEBorderType = "thin"; //TODO: complete the list 40 | 41 | export interface JSEBorder { 42 | type?: JSEBorderType; 43 | color?: number; // TODO: find a better way 44 | } 45 | 46 | export interface JSECellBorder { 47 | left?: JSEBorder; 48 | right?: JSEBorder; 49 | top?: JSEBorder; 50 | bottom?: JSEBorder; 51 | diagonal?: JSEBorder; 52 | } 53 | 54 | export interface JSECellStyle { 55 | font?: JSEFont; //else get default color 56 | //fill?: JSEFill; #Complete Lately 57 | border?: JSECellBorder; 58 | } 59 | 60 | export type JSEContentType = string | number | boolean; 61 | 62 | export interface JSECell extends JSECellStyle { 63 | content?: JSEContentType; 64 | } 65 | 66 | export interface JSEHeaderCell extends JSECell { 67 | 68 | } 69 | 70 | export type JSERow = Array; 71 | export type JSEData = Array; 72 | 73 | export interface JSESheet { 74 | name: string; 75 | columns?: Array; 76 | data: JSEData; 77 | } 78 | 79 | export interface JSExcel { 80 | sheets: Array; 81 | // props: JSEDocumentProps; TODO: create interface for document props 82 | } -------------------------------------------------------------------------------- /src/api/Internals.ts: -------------------------------------------------------------------------------- 1 | export const XMLNS_MAIN: string = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; 2 | export const XMLNS_CONTENT_TYPES: string = "http://schemas.openxmlformats.org/package/2006/content-types"; 3 | export const XMLNS_RELATIONSHIPS: string = "http://schemas.openxmlformats.org/package/2006/relationships"; 4 | export const XMLNS_OFFICE_DOCUMENT_RELATIONSHIPS: string = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; 5 | export const XMLNS_EXTENDED_PROPERTIES: string = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"; 6 | export const XMLNS_CUSTOM_PROPERTIES: string = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; 7 | export const XMLNS_METADATA_CORE_PROPERTIES: string = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; 8 | export const XMLNS_DC_CORE_PROPERTIES: string = "http://purl.org/dc/elements/1.1/"; 9 | export const XMLNS_DC_TERMS_CORE_PROPERTIES: string = "http://purl.org/dc/terms/"; 10 | export const XMLNS_DCMI_TYPE_CORE_PROPERTIES: string = "http://purl.org/dc/dcmitype/"; 11 | export const XMLNS_MC: string = "http://schemas.openxmlformats.org/markup-compatibility/2006"; 12 | export const XMLNS_XSI_XML_SCHEMA_INSTANCE: string = "http://www.w3.org/2001/XMLSchema-instance"; 13 | export const XMLNS_X14AC: string = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"; 14 | export const XMLNS_X16R2: string = "http://schemas.microsoft.com/office/spreadsheetml/2015/02/main"; 15 | export const XMLNS_XR: string = "http://schemas.microsoft.com/office/spreadsheetml/2014/revision"; 16 | export const XMLNS_DOC_PROPS_V_TYPES: string = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; 17 | export const EXTENSION_RELS_SCHEMA: string = "application/vnd.openxmlformats-package.relationships+xml"; 18 | export const EXTENSION_XML_SCHEMA: string = "application/xml"; 19 | export const PART_NAME_XL_WORKBOOK: string = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; 20 | export const PART_NAME_XL_WORKSHEET: string = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"; 21 | export const PART_NAME_XL_THEME: string = "application/vnd.openxmlformats-officedocument.theme+xm"; 22 | export const PART_NAME_XL_STYLES: string = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"; 23 | export const PART_NAME_XL_SHARED_STRINGS: string = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"; 24 | export const PART_NAME_DOC_PROPS_CORE: string = "application/vnd.openxmlformats-package.core-properties+xml"; 25 | export const PART_NAME_DOC_PROPS_APP: string = "application/vnd.openxmlformats-officedocument.extended-properties+xml"; 26 | export const PART_NAME_DOC_PROPS_CUSTOM: string = "application/vnd.openxmlformats-officedocument.custom-properties+xml"; 27 | export const RELATIONSHIP_TYPE_APP: string = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"; 28 | export const RELATIONSHIP_TYPE_CORE: string = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; 29 | export const RELATIONSHIP_TYPE_CUSTOM: string = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties"; 30 | export const RELATION_TYPE_WORKBOOK: string = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; 31 | export const RELATIONSHIP_TARGET_APP: string = "docProps/app.xml"; 32 | export const RELATIONSHIP_TARGET_CORE: string = "docProps/core.xml"; 33 | export const RELATIONSHIP_TARGET_CUSTOM: string = "xl/workbook.xml"; 34 | export const RELATIONSHIP_TARGET_WORKBOOK: string = "docProps/custom.xml"; 35 | export const XMLNS_SST: string = XMLNS_MAIN; 36 | 37 | 38 | /** 39 | * Defaults for Internal use 40 | * */ 41 | export const ENCODING_UTF_8: string = "UTF-8"; 42 | export const DEFAULT_XML_VERSION: string = "1.0"; 43 | export const DEFAULT_STAND_ALONE: boolean = true; 44 | export const DEFAULT_APPLICATION: string = "Microsoft Excel"; 45 | export const DEFAULT_DOC_SECURITY: number = 0; 46 | export const DEFAULT_SCALE_CROP: boolean = false; 47 | export const DEFAULT_WORKSHEETS: string = "Worksheets"; 48 | export const DEFAULT_PUB_DATA: string = "PubData"; 49 | export const DEFAULT_MANAGER: string = "javascript-excel"; 50 | export const DEFAULT_COMPANY: string = "javascript-excel"; 51 | export const DEFAULT_LINKS_UPTO_DATE: boolean = false; 52 | export const DEFAULT_SHARED_DOC: boolean = false; 53 | export const DEFAULT_HYPER_LINKS_CHANGED: boolean = false; 54 | export const DEFAULT_APP_VERSION: string = "16.0300"; 55 | export const DEFAULT_HYPER_LINK_BASE: string = "https://github.com/securedeveloper/javascript-excel"; 56 | export const DEFAULT_PROPS_TITLE: string = "JSE Excel File"; 57 | export const DEFAULT_PROPS_SUBJECT: string = "JSE Excel File"; 58 | export const DEFAULT_PROPS_CREATOR: string = "javascript-excel"; 59 | export const DEFAULT_PROPS_KEYWORDS: string = "javascript-excel"; 60 | export const DEFAULT_PROPS_DESCRIPTION: string = "Excel file built with the help of javascript-excel API"; 61 | export const DEFAULT_PROPS_LAST_MODIFIED_BY: string = "javascript-excel"; 62 | export const DEFAULT_PROPS_CATEGORY: string = "javascript api"; 63 | 64 | /** 65 | * Files, Extensions and Directories 66 | */ 67 | export const FILE_APP: string = "app"; 68 | export const FILE_CORE: string = "core"; 69 | export const FILE_CUSTOM: string = "custom"; 70 | export const FILE_RELS: string = "_rels"; 71 | export const FILE_SHARED_STRINGS: string = "sharedStrings"; 72 | export const FILE_STYLES: string = "styles"; 73 | export const FILE_WORKBOOK: string = "workbook"; 74 | export const EXTENSION_XML: string = ".xml"; 75 | export const EXTENSION_RELS: string = ".rels"; 76 | export const DIRECTORY_DOC_PROPS: string = "docProps"; 77 | -------------------------------------------------------------------------------- /src/api/JavaScriptExcel.ts: -------------------------------------------------------------------------------- 1 | import {JSEData, JSERow} from "../Types"; 2 | 3 | export default class JavaScriptExcel { 4 | private ___Excel___: any; 5 | private ___SAVE_AS___: any; 6 | private data: JSEData; 7 | 8 | constructor(jszip: any, saveAs: any) { 9 | this.___Excel___ = new jszip(); 10 | this.___SAVE_AS___ = saveAs; 11 | this.data = []; 12 | } 13 | 14 | public setData(data: JSEData): void { 15 | if (data) { 16 | this.data = data; 17 | } else { 18 | throw ("Data is not specified or in bad shape"); 19 | } 20 | } 21 | 22 | public downloadExcel = (): void => { 23 | this.___Excel___.generateAsync({type: "blob"}).then(this.saveExcelFile); 24 | }; 25 | 26 | private saveExcelFile = (excelContent: any) => { 27 | this.___SAVE_AS___(excelContent, "Download.xlsx"); // TODO: Get File Name 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/api/constants.ts: -------------------------------------------------------------------------------- 1 | export type ___JSE_DownloadFileExtension = ".xlsx" | ".csv"; // TODO: Complete extension list 2 | export const DEFAULT_FILE_NAME: string = "Download"; 3 | export const DEFAULT_FILE_EXTENSION: ___JSE_DownloadFileExtension = ".xlsx"; 4 | 5 | export const DEFAULT_FONT_SIZE: number = 11; 6 | export const DEFAULT_FONT_COLOR: string = "000000"; 7 | export const DEFAULT_FONT_NAME: string = "Calibri"; 8 | -------------------------------------------------------------------------------- /src/api/xlsx.ts: -------------------------------------------------------------------------------- 1 | type ___JSE_XLSX___SupportedEncoding = "UTF-8"; // TODO: Add more encoding support 2 | type ___JSE_XLSX___NodeName = 3 | "Types" 4 | | "Default" 5 | | "Override" 6 | | "Relationships" 7 | | "Relationship" 8 | | "Properties" 9 | | "Application" 10 | | "DocSecurity" 11 | | "ScaleCrop" 12 | | "HeadingPairs" 13 | | "vt:vector" // TODO: Could be a separate Node/Type/Interface 14 | | "vt:variant" // TODO: Could be a separate Node/Type/Interface 15 | | "vt:lpstr" 16 | | "vt:i4" 17 | | "TitlesOfParts" | "Company" | "LinksUpToDate" | "SharedDoc" | "HyperlinksChanged" | "AppVersion" 18 | | "cp:coreProperties" // TODO: Could be a separate Node/Type/Interface 19 | | "dc:creator" 20 | | "cp:lastModifiedBy" 21 | | "dcterms:created" 22 | | "dcterms:modified" 23 | | ""; // TODO: Improve further 24 | type ___JSE_XLSX___NodeKey = 25 | "xmlns" 26 | | "xmlns:vt" 27 | | "xmlns:cp" 28 | | "xmlns:dc" 29 | | "xmlns:dcterms" 30 | | "xmlns:dcmitype" 31 | | "xmlns:xsi" 32 | | "Extension" 33 | | "ContentType" 34 | | "PartName" 35 | | "Id" 36 | | "Type" 37 | | "Target" 38 | | "size" 39 | | "baseType" // TODO: Could be enum 40 | | "xsi:type" // TODO: Could be enum 41 | | ""; 42 | 43 | type ___JSE_XLSX___FileExtensionFormat = ".xml" | ".rels"; 44 | type ___JSE_XLSX___FileExtension = ___JSE_XLSX___FileExtensionFormat | Array<___JSE_XLSX___FileExtensionFormat>; 45 | type ___JSE_XLSX___ThemeName = "theme1"; // TODO: Improve further of go with string 46 | type ___JSE_XLSX___SheetName = "sheet" | "sheet1" | string; // TODO: Improve further of go with string 47 | type ___JSE_XLSX___PrinterSettingName = "printerSettings1"; // TODO: Improve further of go with string 48 | type ___JSE_XLSX___TableName = "table1"; // TODO: Improve further of go with string 49 | type ___JSE_XLSX___FileName = 50 | "[Content_Types]" 51 | | "app" 52 | | "core" 53 | | "custom" 54 | | "workbook" 55 | | "sharedStrings" 56 | | "styles" 57 | | ___JSE_XLSX___ThemeName 58 | | ___JSE_XLSX___SheetName 59 | | ___JSE_XLSX___TableName 60 | | ___JSE_XLSX___PrinterSettingName 61 | | null; 62 | type ___JSE_XLSX___DirectoryName = 63 | "_rels" 64 | | "docProps" 65 | | "xl" 66 | | "Book1" 67 | | "printerSettings" 68 | | "tables" 69 | | "themes" 70 | | "worksheets"; 71 | 72 | interface ___JSE_XLSX___XMLTag { 73 | // TODO: Verify Tag add more props if needed 74 | version: string; 75 | encoding: ___JSE_XLSX___SupportedEncoding; 76 | standalone?: boolean; 77 | } 78 | 79 | interface ___JSE_XLSX___NodeAttribute { 80 | key: string | ___JSE_XLSX___NodeKey; // TODO: Make precise if possible 81 | value: string | number | boolean; // TODO: Improve if needed 82 | } 83 | 84 | type ___JSE_XLSX___Node_CONTENT_TYPE = ___JSE_XLSX___Node | string | number | boolean | undefined; 85 | 86 | export interface ___JSE_XLSX___Node { 87 | name: string | ___JSE_XLSX___NodeName; // TODO: Make Precise if possible 88 | values?: Array<___JSE_XLSX___NodeAttribute>; 89 | content?: ___JSE_XLSX___Node_CONTENT_TYPE | Array<___JSE_XLSX___Node_CONTENT_TYPE>; 90 | } 91 | 92 | export interface ___JSE_XLSX___FileContent { 93 | xml?: ___JSE_XLSX___XMLTag; 94 | content: ___JSE_XLSX___Node; // TODO: Verify if nested Nodes are needed in any file 95 | } 96 | 97 | export interface ___JSE_XLSX___File { 98 | fileName: ___JSE_XLSX___FileName; 99 | fileExtension: ___JSE_XLSX___FileExtension; 100 | fileContent: ___JSE_XLSX___FileContent; 101 | // TODO: add further file info as needed and verify later on 102 | } 103 | 104 | export interface ___JSE_XLSX___Directory { 105 | directoryName: ___JSE_XLSX___DirectoryName; 106 | content?: ___JSE_XLSX___File | Array<___JSE_XLSX___File> | ___JSE_XLSX___Directory | Array<___JSE_XLSX___Directory>; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import {___JSE_DownloadFileExtension} from "./api/constants"; 2 | import JavascriptExcel from "./api/JavaScriptExcel"; 3 | 4 | interface IJavaScriptExcel { 5 | new(jszip: any, saveAs: Function): JavascriptExcel; 6 | } 7 | 8 | export declare module JSExcel { 9 | export type JSEFileExtension = ___JSE_DownloadFileExtension; 10 | export type JSXLX = IJavaScriptExcel; 11 | //TODO: Complete module export here 12 | } 13 | 14 | export default JavascriptExcel; 15 | -------------------------------------------------------------------------------- /src/util/ExcelUtil.ts: -------------------------------------------------------------------------------- 1 | import { JSECell, JSEFont, JSEHeaderCell, JSERow, JSESheet, JSExcel, JSEBorder, JSECellBorder } from "../Types"; 2 | 3 | export function excelTotalCellCounter(excel: JSExcel): number { 4 | if (excel == null || excel == undefined || excel.sheets == undefined) return 0; 5 | 6 | return excel.sheets.map(sheetTotalCellCounter).reduce(add, 0); 7 | } 8 | 9 | function sheetTotalCellCounter(sheet: JSESheet): number { 10 | if (sheet == null || sheet == undefined) return 0; 11 | const { columns, data } = sheet; 12 | 13 | return columns ? columns.length + data.map(rowTotalCellCounter).reduce(add, 0) : data.map(rowTotalCellCounter).reduce(add, 0); 14 | } 15 | 16 | function rowTotalCellCounter(row: JSERow) { 17 | if (row == null || row == undefined) return 0; 18 | 19 | return row.length; 20 | } 21 | 22 | function add(item1: number, item2: number) { 23 | return item1 + item2; 24 | } 25 | 26 | /** 27 | * Fonts utility/helper functions 28 | */ 29 | 30 | export function hasFontsInExcel(excel: JSExcel): boolean { 31 | if (excel == null || excel == undefined) return false; 32 | 33 | return excel.sheets.some(hasFontInSheet); 34 | } 35 | 36 | function hasFontInSheet(sheet: JSESheet): boolean { 37 | if (sheet == null || sheet == undefined) return false; 38 | 39 | return (sheet.columns && sheet.columns.some(hasFontInCell)) || sheet.data.some(row => row.some(hasFontInCell)); 40 | } 41 | 42 | function hasFontInCell(cell: JSECell): boolean { 43 | if (cell == null || cell == undefined) return false; 44 | 45 | return !!(cell.font && cell.font.name); 46 | } 47 | 48 | export function extractFontsFromExcel(excel: JSExcel): Array { 49 | if (excel == null || excel == undefined) return []; 50 | 51 | return excel.sheets.flatMap(getFontsFromSheet); 52 | } 53 | 54 | function getFontsFromSheet(sheet: JSESheet): Array { 55 | const fonts: Array = []; 56 | 57 | if (sheet.columns) { 58 | sheet.columns.map((col: JSEHeaderCell) => { 59 | if (col.font) { 60 | fonts.push(col.font); 61 | } 62 | }); 63 | } 64 | 65 | if (sheet.data) { 66 | sheet.data.forEach((row: JSERow) => { 67 | row.forEach((col: JSECell) => { 68 | if (col.font) { 69 | fonts.push(col.font); 70 | } 71 | }); 72 | }); 73 | } 74 | 75 | return fonts; 76 | } 77 | 78 | /** 79 | * Fills utility/helper functions 80 | * */ 81 | 82 | /* 83 | export function hasFillsInExcel(excel: JSExcel): boolean { 84 | if (excel == null || excel == undefined) return false; 85 | 86 | return excel.sheets.some(hasFillsInSheet); 87 | } 88 | 89 | function hasFillsInSheet(sheet: JSESheet): boolean { 90 | if (sheet == null || sheet == undefined) return false; 91 | 92 | return (sheet.columns && sheet.columns.some(hasFillsInCell)) || sheet.data.some(row => row.some(hasFillsInCell)); 93 | } 94 | 95 | function hasFillsInCell(cell: JSECell): boolean { 96 | if (cell == null || cell == undefined) return false; 97 | 98 | return !!(cell.fill && cell.fille.patternFill); 99 | } 100 | 101 | export function extractFillsFromExcel(excel: JSExcel): Array { 102 | if (excel == null || excel == undefined) return []; 103 | 104 | return excel.sheets.flatMap(extractFillsFromSheet); 105 | } 106 | 107 | function extractFillsFromSheet(sheet: JSESheet): Array { 108 | const fills: Array = []; 109 | 110 | if (sheet.columns) { 111 | sheet.columns.map((col: JSEHeaderCell) => { 112 | if (col.font) { 113 | fills.push(col.fill); 114 | } 115 | }); 116 | } 117 | 118 | if (sheet.data) { 119 | sheet.data.forEach((row: JSERow) => { 120 | row.forEach((col: JSECell) => { 121 | if (col.fill) { 122 | fills.push(col.fill); 123 | } 124 | }); 125 | }); 126 | } 127 | 128 | return fills; 129 | } 130 | */ 131 | 132 | export function hasBordersInExcel(excel: JSExcel): boolean { 133 | if (excel == null || excel == undefined) return false; 134 | 135 | return excel.sheets.some(hasBordersInSheet); 136 | } 137 | 138 | function hasBordersInSheet(sheet: JSESheet): boolean { 139 | if (sheet == null || sheet == undefined) return false; 140 | 141 | return (sheet.columns && sheet.columns.some(hasBordersInCell)) || sheet.data.some(row => row.some(hasBordersInCell)); 142 | } 143 | 144 | function hasBordersInCell(cell: JSECell): boolean { 145 | if (cell == null || cell == undefined) return false; 146 | 147 | return !!(cell.font && cell.font.name); 148 | } 149 | 150 | export function extractBordersFromExcel(excel: JSExcel): Array { 151 | if (excel == null || excel == undefined) return []; 152 | 153 | return excel.sheets.flatMap(getBordersFromSheet); 154 | } 155 | 156 | function getBordersFromSheet(sheet: JSESheet): Array { 157 | const borders: Array = []; 158 | 159 | if (sheet.columns) { 160 | sheet.columns.map((col: JSEHeaderCell) => { 161 | if (col.border) { 162 | borders.push(col.border); 163 | } 164 | }); 165 | } 166 | 167 | if (sheet.data) { 168 | sheet.data.forEach((row: JSERow) => { 169 | row.forEach((col: JSECell) => { 170 | if (col.border) { 171 | borders.push(col.border); 172 | } 173 | }); 174 | }); 175 | } 176 | 177 | return borders; 178 | } -------------------------------------------------------------------------------- /src/util/Helper.ts: -------------------------------------------------------------------------------- 1 | export function cleanAlphaNumericString(str: string): string { 2 | return (str && typeof str === "string") ? str.replace(/\W/g, '') : str; 3 | } 4 | 5 | export function getISOFormattedDate(date?: Date): string { 6 | if (!date || typeof date !== "object") { 7 | date = new Date(); 8 | } 9 | 10 | return date.toISOString().split('.')[0] + "Z"; 11 | } 12 | -------------------------------------------------------------------------------- /src/xlsx/FileContentTypes.ts: -------------------------------------------------------------------------------- 1 | import {___JSE_XLSX___File, ___JSE_XLSX___FileContent, ___JSE_XLSX___Node} from "../api/xlsx"; 2 | import { 3 | EXTENSION_RELS_SCHEMA, 4 | EXTENSION_XML_SCHEMA, 5 | PART_NAME_DOC_PROPS_APP, 6 | PART_NAME_DOC_PROPS_CORE, 7 | PART_NAME_DOC_PROPS_CUSTOM, 8 | PART_NAME_XL_SHARED_STRINGS, 9 | PART_NAME_XL_WORKSHEET, 10 | PART_NAME_XL_STYLES, 11 | PART_NAME_XL_THEME, 12 | PART_NAME_XL_WORKBOOK, 13 | XMLNS_CONTENT_TYPES, 14 | DEFAULT_XML_VERSION, 15 | ENCODING_UTF_8, 16 | DEFAULT_STAND_ALONE 17 | } from "../api/Internals"; 18 | import {JSESheet, JSExcel} from "../Types"; 19 | import {DEFAULT_FILE_EXTENSION} from "../api/constants"; 20 | import {cleanAlphaNumericString} from "../util/Helper"; 21 | 22 | const fileProps: any = { 23 | name: "[Content_Types]", 24 | extension: DEFAULT_FILE_EXTENSION, 25 | version: DEFAULT_XML_VERSION, 26 | encoding: ENCODING_UTF_8, 27 | standalone: DEFAULT_STAND_ALONE, 28 | nodes: { 29 | Types: "Types", 30 | Default: "Default", 31 | Override: "Override" 32 | }, 33 | keys: { 34 | xmlns: "xmlns", 35 | Extension: "Extension", 36 | ContentType: "ContentType", 37 | PartName: "PartName" 38 | }, 39 | values: { 40 | rels: "rels", 41 | xml: "xml", 42 | PartName_xml: "/xl/workbook.xml" 43 | } 44 | }; 45 | 46 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 47 | fileName: fileProps.name, 48 | fileExtension: fileProps.extension, 49 | fileContent: getContentTypeNodes(excel) 50 | }); 51 | 52 | function getContentTypeNodes(excel: JSExcel): ___JSE_XLSX___FileContent { 53 | return { 54 | xml: { 55 | version: fileProps.version, 56 | encoding: fileProps.encoding, 57 | standalone: fileProps.standalone 58 | }, 59 | content: { 60 | name: fileProps.nodes.Types, 61 | values: [{key: fileProps.keys.xmlns, value: XMLNS_CONTENT_TYPES}], 62 | content: [ 63 | { 64 | name: fileProps.nodes.Default, 65 | values: 66 | [ 67 | {key: fileProps.keys.Extension, value: fileProps.values.rels}, 68 | {key: fileProps.keys.ContentType, value: EXTENSION_RELS_SCHEMA} 69 | ] 70 | }, 71 | { 72 | name: fileProps.nodes.Default, 73 | values: 74 | [ 75 | {key: fileProps.keys.Extension, value: fileProps.values.xml}, 76 | {key: fileProps.keys.ContentType, value: EXTENSION_XML_SCHEMA} 77 | ] 78 | }, 79 | //xl folder contents 80 | { 81 | //workbook 82 | name: fileProps.nodes.Override, 83 | values: 84 | [ 85 | {key: fileProps.keys.PartName, value: fileProps.values.PartName_xml}, 86 | {key: fileProps.keys.ContentType, value: PART_NAME_XL_WORKBOOK} 87 | ] 88 | }, 89 | ...getWorkSheetsOverrides(excel), 90 | ...getThemesOverrides(excel), 91 | ...getStylesOverrides(excel), 92 | ...getSharedStringsOverrides(excel), 93 | ...getPropsOverrides(excel), 94 | ] 95 | } 96 | } 97 | } 98 | 99 | function getWorkSheetsOverrides(excel: JSExcel): Array<___JSE_XLSX___Node> { 100 | const partNameOverride: string = "/xl/worksheets/"; 101 | 102 | return excel.sheets.map((sheet: JSESheet) => ({ 103 | name: fileProps.nodes.Override, 104 | values: [ 105 | { 106 | key: fileProps.keys.PartName, 107 | value: `${partNameOverride}${cleanAlphaNumericString(sheet.name)}${fileProps.extension}` 108 | }, 109 | {key: fileProps.keys.ContentType, value: PART_NAME_XL_WORKSHEET} 110 | ] 111 | })); 112 | } 113 | 114 | function getThemesOverrides(excel: JSExcel): Array<___JSE_XLSX___Node> { 115 | const partNameOverride: string = "/xl/theme/"; 116 | 117 | // TODO: Complete Overrides 118 | return [{ 119 | name: fileProps.nodes.Override, 120 | values: [ 121 | {key: fileProps.keys.PartName, value: `${partNameOverride}theme1${fileProps.extension}`}, 122 | {key: fileProps.keys.ContentType, value: PART_NAME_XL_THEME} 123 | ] 124 | }]; 125 | } 126 | 127 | function getStylesOverrides(excel: JSExcel): Array<___JSE_XLSX___Node> { 128 | const partNameOverride: string = "/xl/styles"; 129 | 130 | // TODO: Complete Overrides 131 | return [{ 132 | name: fileProps.nodes.Override, 133 | values: [ 134 | {key: fileProps.keys.PartName, value: `${partNameOverride}${fileProps.extension}`}, 135 | {key: fileProps.keys.ContentType, value: PART_NAME_XL_STYLES} 136 | ] 137 | }]; 138 | } 139 | 140 | function getSharedStringsOverrides(excel: JSExcel): Array<___JSE_XLSX___Node> { 141 | const partNameOverride: string = "/xl/sharedStrings"; 142 | 143 | // TODO: Complete Overrides 144 | return [{ 145 | name: fileProps.nodes.Override, 146 | values: [ 147 | {key: fileProps.keys.PartName, value: `${partNameOverride}${fileProps.extension}`}, 148 | {key: fileProps.keys.ContentType, value: PART_NAME_XL_SHARED_STRINGS} 149 | ] 150 | }]; 151 | } 152 | 153 | function getPropsOverrides(excel: JSExcel): Array<___JSE_XLSX___Node> { 154 | const partNameOverride: string = "/docProps/"; 155 | 156 | return [ 157 | { 158 | name: fileProps.nodes.Override, 159 | values: [ 160 | {key: fileProps.keys.PartName, value: `${partNameOverride}core${fileProps.extension}`}, 161 | {key: fileProps.keys.ContentType, value: PART_NAME_DOC_PROPS_CORE} 162 | ] 163 | }, 164 | { 165 | name: fileProps.nodes.Override, 166 | values: [ 167 | {key: fileProps.keys.PartName, value: `${partNameOverride}app${fileProps.extension}`}, 168 | {key: fileProps.keys.ContentType, value: PART_NAME_DOC_PROPS_APP} 169 | ] 170 | }, 171 | // ...getCustomPropsOverrider(excel) TODO: Implement when doc props interface is available and only custom props are provided 172 | ]; 173 | } 174 | 175 | function getCustomPropsOverrider(excel: JSExcel): ___JSE_XLSX___Node { 176 | // if(!excel.props.customProps) return; TODO: finish it 177 | 178 | const partNameOverride: string = "/docProps/custom"; 179 | 180 | return { 181 | name: fileProps.nodes.Override, 182 | values: [ 183 | {key: fileProps.keys.PartName, value: `${partNameOverride}${fileProps.extension}`}, 184 | {key: fileProps.keys.ContentType, value: PART_NAME_DOC_PROPS_CUSTOM} 185 | ] 186 | }; 187 | } -------------------------------------------------------------------------------- /src/xlsx/_rels/DirectoryRels.ts: -------------------------------------------------------------------------------- 1 | import {JSExcel} from "../../Types"; 2 | import { 3 | ___JSE_XLSX___Directory, 4 | ___JSE_XLSX___File, 5 | ___JSE_XLSX___FileContent, 6 | ___JSE_XLSX___Node 7 | } from "../../api/xlsx"; 8 | import { 9 | RELATIONSHIP_TARGET_APP, 10 | RELATIONSHIP_TARGET_CORE, 11 | RELATIONSHIP_TARGET_CUSTOM, 12 | RELATIONSHIP_TARGET_WORKBOOK, 13 | RELATIONSHIP_TYPE_APP, 14 | RELATIONSHIP_TYPE_CORE, 15 | RELATIONSHIP_TYPE_CUSTOM, 16 | RELATION_TYPE_WORKBOOK, 17 | XMLNS_RELATIONSHIPS, 18 | EXTENSION_RELS, 19 | DEFAULT_XML_VERSION, 20 | ENCODING_UTF_8, 21 | DEFAULT_STAND_ALONE, FILE_RELS 22 | } from "../../api/Internals"; 23 | 24 | const fileProps: any = { 25 | name: null, 26 | extension: EXTENSION_RELS, 27 | version: DEFAULT_XML_VERSION, 28 | encoding: ENCODING_UTF_8, 29 | standalone: DEFAULT_STAND_ALONE, 30 | nodes: { 31 | Relationships: "Relationships", 32 | Relationship: "Relationship" 33 | }, 34 | keys: { 35 | xmlns: "xmlns", 36 | Id: "Id", 37 | Type: "Type", 38 | Target: "Target" 39 | }, 40 | values: { 41 | Id_rId3: "rId3", 42 | Id_rId2: "rId2", 43 | Id_rId1: "rId1", 44 | Id_rId4: "rId4" 45 | } 46 | }; 47 | 48 | const directorProps: any = { 49 | name: FILE_RELS, 50 | files: {rels: {...fileProps}} 51 | }; 52 | 53 | export default (excel: JSExcel): ___JSE_XLSX___Directory => ({ 54 | directoryName: directorProps.name, 55 | content: getRelDirectoryFiles(excel) 56 | }); 57 | 58 | function getRelDirectoryFiles(excel: JSExcel): ___JSE_XLSX___File { 59 | return { 60 | fileName: fileProps.name, 61 | fileExtension: fileProps.extension, 62 | fileContent: getRelsNodes(excel) 63 | }; 64 | } 65 | 66 | function getRelsNodes(excel: JSExcel): ___JSE_XLSX___FileContent { 67 | return { 68 | xml: { 69 | version: fileProps.version, 70 | encoding: fileProps.encoding, 71 | standalone: fileProps.standalone 72 | }, 73 | content: { 74 | name: fileProps.nodes.Relationships, 75 | values: [{key: fileProps.keys.xmlns, value: XMLNS_RELATIONSHIPS}], 76 | content: [ 77 | { 78 | name: fileProps.nodes.Relationship, 79 | values: [ 80 | {key: fileProps.keys.Id, value: fileProps.values.Id_rId3}, 81 | {key: fileProps.keys.Type, value: RELATIONSHIP_TYPE_APP}, 82 | {key: fileProps.keys.Target, value: RELATIONSHIP_TARGET_APP} 83 | ] 84 | }, 85 | { 86 | name: fileProps.nodes.Relationship, 87 | values: [ 88 | {key: fileProps.keys.Id, value: fileProps.values.Id_rId2}, 89 | {key: fileProps.keys.Type, value: RELATIONSHIP_TYPE_CORE}, 90 | {key: fileProps.keys.Target, value: RELATIONSHIP_TARGET_CORE} 91 | ] 92 | }, 93 | { 94 | name: fileProps.nodes.Relationship, 95 | values: [ 96 | {key: fileProps.keys.Id, value: fileProps.values.Id_rId1}, 97 | {key: fileProps.keys.Type, value: RELATION_TYPE_WORKBOOK}, 98 | {key: fileProps.keys.Target, value: RELATIONSHIP_TARGET_WORKBOOK} 99 | ] 100 | }, 101 | // ...getCustomRelationshipNode(excel) TODO: finish when file custom props are implemented 102 | ] 103 | } 104 | }; 105 | } 106 | 107 | function getCustomRelationshipNode(excel: JSExcel): ___JSE_XLSX___Node { 108 | //TODO: return if custom values are provided 109 | return { 110 | name: fileProps.nodes.Relationship, 111 | values: [ 112 | {key: fileProps.keys.Id, value: fileProps.values.Id_rId4}, 113 | {key: fileProps.keys.Type, value: RELATIONSHIP_TYPE_CUSTOM}, 114 | {key: fileProps.keys.Target, value: RELATIONSHIP_TARGET_CUSTOM} 115 | ] 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /src/xlsx/docProps/DirectoryDocsProps.ts: -------------------------------------------------------------------------------- 1 | // TODO: Tier-02 Replace values when file properties module is implemented 2 | import {JSExcel} from "../../Types"; 3 | import {___JSE_XLSX___Directory, ___JSE_XLSX___File} from "../../api/xlsx"; 4 | import {DIRECTORY_DOC_PROPS} from "../../api/Internals"; 5 | import appFile from "./FileDocPropsApp"; 6 | import coreFile from "./FileDocPropsCore"; 7 | import customFile from "./FileDocPropsCustom"; 8 | 9 | const directoryProps: any = { 10 | name: DIRECTORY_DOC_PROPS 11 | }; 12 | 13 | export default (excel: JSExcel): ___JSE_XLSX___Directory => ({ 14 | directoryName: directoryProps.name, 15 | content: getRelDirectoryFiles(excel) 16 | }); 17 | 18 | function getRelDirectoryFiles(excel: JSExcel): Array<___JSE_XLSX___File> { 19 | return [appFile(excel), coreFile(excel), customFile(excel)]; 20 | } 21 | -------------------------------------------------------------------------------- /src/xlsx/docProps/FileDocPropsApp.ts: -------------------------------------------------------------------------------- 1 | // TODO: Tier-02 Replace values when file properties module is implemented 2 | import {JSExcel} from "../../Types"; 3 | import {___JSE_XLSX___File, ___JSE_XLSX___Node} from "../../api/xlsx"; 4 | import { 5 | DEFAULT_APP_VERSION, 6 | DEFAULT_APPLICATION, 7 | DEFAULT_COMPANY, 8 | DEFAULT_DOC_SECURITY, 9 | DEFAULT_HYPER_LINK_BASE, 10 | DEFAULT_HYPER_LINKS_CHANGED, 11 | DEFAULT_LINKS_UPTO_DATE, 12 | DEFAULT_MANAGER, 13 | DEFAULT_PUB_DATA, 14 | DEFAULT_SCALE_CROP, 15 | DEFAULT_SHARED_DOC, 16 | DEFAULT_WORKSHEETS, 17 | XMLNS_EXTENDED_PROPERTIES, 18 | XMLNS_DOC_PROPS_V_TYPES, 19 | EXTENSION_XML, 20 | DEFAULT_XML_VERSION, 21 | ENCODING_UTF_8, 22 | DEFAULT_STAND_ALONE, 23 | FILE_APP 24 | } from "../../api/Internals"; 25 | 26 | const fileProps: any = { 27 | name: FILE_APP, 28 | extension: EXTENSION_XML, 29 | xml: { 30 | version: DEFAULT_XML_VERSION, 31 | encoding: ENCODING_UTF_8, 32 | standalone: DEFAULT_STAND_ALONE 33 | }, 34 | nodes: { 35 | Properties: "Properties", 36 | Application: "Application", 37 | DocSecurity: "DocSecurity", 38 | ScaleCrop: "ScaleCrop", 39 | HeadingPairs: "HeadingPairs", 40 | TitlesOfParts: "TitlesOfParts", 41 | Manager: "Manager", 42 | Company: "Company", 43 | LinksUpToDate: "LinksUpToDate", 44 | SharedDoc: "SharedDoc", 45 | HyperlinkBase: "HyperlinkBase", 46 | HyperlinksChanged: "HyperlinksChanged", 47 | AppVersion: "AppVersion", 48 | VtVector: "vt:vector", 49 | VtVariant: "vt:variant", 50 | VtLpstr: "vt:lpstr", 51 | VtI4: "vt:i4" 52 | }, 53 | keys: { 54 | xmlns: "xmlns", 55 | xmlnsVt: "xmlns:vt", 56 | size: "size", 57 | baseType: "baseType" 58 | }, 59 | values: { 60 | variant: "variant", 61 | lpstr: "lpstr" 62 | } 63 | }; 64 | 65 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 66 | fileName: fileProps.name, 67 | fileExtension: fileProps.extension, 68 | fileContent: { 69 | xml: { 70 | ...fileProps.xml 71 | }, 72 | content: { 73 | name: fileProps.nodes.Properties, 74 | values: [ 75 | {key: fileProps.keys.xmlns, value: XMLNS_EXTENDED_PROPERTIES}, 76 | {key: fileProps.keys.xmlnsVt, value: XMLNS_DOC_PROPS_V_TYPES} 77 | ], 78 | content: [ 79 | getApplicationNode(excel), 80 | getDocSecurityNode(excel), 81 | getScaleCropNode(excel), 82 | getHeadingPairsNode(excel), 83 | getTitlesOfPartsNode(excel), 84 | getManagerNode(excel), 85 | getCompanyNode(excel), 86 | getLinksUpToDateNode(excel), 87 | getSharedDocNode(excel), 88 | getHyperlinkBaseNode(excel), 89 | getHyperlinksChangedNode(excel), 90 | getAppVersionNode(excel), 91 | ] 92 | } 93 | } 94 | }); 95 | 96 | function getApplicationNode(excel: JSExcel): ___JSE_XLSX___Node { 97 | return { 98 | name: fileProps.nodes.Application, 99 | content: DEFAULT_APPLICATION 100 | }; 101 | } 102 | 103 | function getDocSecurityNode(excel: JSExcel): ___JSE_XLSX___Node { 104 | return { 105 | name: fileProps.nodes.DocSecurity, 106 | content: DEFAULT_DOC_SECURITY 107 | }; 108 | } 109 | 110 | function getScaleCropNode(excel: JSExcel): ___JSE_XLSX___Node { 111 | return { 112 | name: fileProps.nodes.ScaleCrop, 113 | content: DEFAULT_SCALE_CROP 114 | }; 115 | } 116 | 117 | function getHeadingPairsNode(excel: JSExcel): ___JSE_XLSX___Node { 118 | return { 119 | name: fileProps.nodes.HeadingPairs, 120 | content: { 121 | name: fileProps.nodes.VtVector, 122 | values: [ 123 | {key: fileProps.keys.size, value: 2}, 124 | {key: fileProps.keys.baseType, value: fileProps.values.variant} 125 | ], 126 | content: [ 127 | { 128 | name: fileProps.nodes.VtVariant, 129 | content: { 130 | name: fileProps.nodes.VtLpstr, 131 | content: DEFAULT_WORKSHEETS 132 | } 133 | }, 134 | { 135 | name: fileProps.nodes.VtVariant, 136 | content: { 137 | name: fileProps.nodes.VtI4, 138 | content: 1 139 | } 140 | } 141 | ] 142 | } 143 | 144 | }; 145 | } 146 | 147 | function getTitlesOfPartsNode(excel: JSExcel): ___JSE_XLSX___Node { 148 | return { 149 | name: fileProps.nodes.TitlesOfParts, 150 | content: { 151 | name: fileProps.nodes.VtVector, 152 | values: [ 153 | {key: fileProps.keys.size, value: 1}, 154 | {key: fileProps.keys.baseType, value: fileProps.values.lpstr} 155 | ], 156 | content: { 157 | name: fileProps.nodes.VtLpstr, 158 | content: DEFAULT_PUB_DATA 159 | } 160 | } 161 | }; 162 | } 163 | 164 | function getManagerNode(excel: JSExcel): ___JSE_XLSX___Node { 165 | return { 166 | name: fileProps.nodes.Manager, 167 | content: DEFAULT_MANAGER 168 | }; 169 | } 170 | 171 | function getCompanyNode(excel: JSExcel): ___JSE_XLSX___Node { 172 | return { 173 | name: fileProps.nodes.Company, 174 | content: DEFAULT_COMPANY 175 | }; 176 | } 177 | 178 | function getLinksUpToDateNode(excel: JSExcel): ___JSE_XLSX___Node { 179 | return { 180 | name: fileProps.nodes.LinksUpToDate, 181 | content: DEFAULT_LINKS_UPTO_DATE 182 | }; 183 | } 184 | 185 | function getSharedDocNode(excel: JSExcel): ___JSE_XLSX___Node { 186 | return { 187 | name: fileProps.nodes.SharedDoc, 188 | content: DEFAULT_SHARED_DOC 189 | }; 190 | } 191 | 192 | function getHyperlinkBaseNode(excel: JSExcel): ___JSE_XLSX___Node { 193 | return { 194 | name: fileProps.nodes.HyperlinkBase, 195 | content: DEFAULT_HYPER_LINK_BASE 196 | }; 197 | } 198 | 199 | function getHyperlinksChangedNode(excel: JSExcel): ___JSE_XLSX___Node { 200 | return { 201 | name: fileProps.nodes.HyperlinksChanged, 202 | content: DEFAULT_HYPER_LINKS_CHANGED 203 | }; 204 | } 205 | 206 | function getAppVersionNode(excel: JSExcel): ___JSE_XLSX___Node { 207 | return { 208 | name: fileProps.nodes.AppVersion, 209 | content: DEFAULT_APP_VERSION 210 | }; 211 | } 212 | -------------------------------------------------------------------------------- /src/xlsx/docProps/FileDocPropsCore.ts: -------------------------------------------------------------------------------- 1 | // TODO: Tier-02 Replace values when file properties module is implemented 2 | import {JSExcel} from "../../Types"; 3 | import {___JSE_XLSX___File, ___JSE_XLSX___Node} from "../../api/xlsx"; 4 | import {getISOFormattedDate} from "../../util/Helper"; 5 | import { 6 | DEFAULT_PROPS_CREATOR, 7 | DEFAULT_PROPS_DESCRIPTION, 8 | DEFAULT_PROPS_KEYWORDS, 9 | DEFAULT_PROPS_LAST_MODIFIED_BY, 10 | DEFAULT_PROPS_SUBJECT, 11 | DEFAULT_PROPS_TITLE, 12 | DEFAULT_STAND_ALONE, 13 | DEFAULT_XML_VERSION, 14 | ENCODING_UTF_8, 15 | EXTENSION_XML, 16 | FILE_CORE, 17 | XMLNS_METADATA_CORE_PROPERTIES, 18 | XMLNS_DC_CORE_PROPERTIES, 19 | XMLNS_DCMI_TYPE_CORE_PROPERTIES, 20 | XMLNS_DC_TERMS_CORE_PROPERTIES, 21 | XMLNS_XSI_XML_SCHEMA_INSTANCE 22 | } from "../../api/Internals"; 23 | 24 | const fileProps: any = { 25 | xml: { 26 | version: DEFAULT_XML_VERSION, 27 | encoding: ENCODING_UTF_8, 28 | standalone: DEFAULT_STAND_ALONE 29 | }, 30 | name: FILE_CORE, 31 | extension: EXTENSION_XML, 32 | nodes: { 33 | cpCoreProperties: "cp:coreProperties", 34 | dcTitle: "dc:title", 35 | dcSubject: "dc:subject", 36 | dcCreator: "dc:creator", 37 | dcKeywords: "dc:keywords", 38 | dcDescription: "dc:description", 39 | cpLastModifiedBy: "cp:lastModifiedBy", 40 | dcTermsCreated: "dcterms:created", 41 | dcTermsModified: "dcterms:modified", 42 | cpCategory: "cp:category", 43 | }, 44 | keys: { 45 | xmlnsCp: "xmlns:cp", 46 | xmlnsDc: "xmlns:dc", 47 | xmlnsDcterms: "xmlns:dcterms", 48 | xmlnsDcmitype: "xmlns:dcmitype", 49 | xmlnsXsi: "xmlns:xsi", 50 | xsiType: "xsi:type" 51 | }, 52 | values: { 53 | xsiType: "dcterms:W3CDTF" 54 | } 55 | }; 56 | 57 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 58 | fileName: fileProps.name, 59 | fileExtension: fileProps.extension, 60 | fileContent: { 61 | xml: {...fileProps.xml}, 62 | content: { 63 | name: fileProps.nodes.cpCoreProperties, 64 | values: [ 65 | {key: fileProps.keys.xmlnsCp, value: XMLNS_METADATA_CORE_PROPERTIES}, 66 | {key: fileProps.keys.xmlnsDc, value: XMLNS_DC_CORE_PROPERTIES}, 67 | {key: fileProps.keys.xmlnsDcterms, value: XMLNS_DC_TERMS_CORE_PROPERTIES}, 68 | {key: fileProps.keys.xmlnsDcmitype, value: XMLNS_DCMI_TYPE_CORE_PROPERTIES}, 69 | {key: fileProps.keys.xmlnsXsi, value: XMLNS_XSI_XML_SCHEMA_INSTANCE} 70 | ], 71 | content: [ 72 | getTitleNode(excel), 73 | getSubjectNode(excel), 74 | getCreatorNode(excel), 75 | getKeywordsNode(excel), 76 | getDescriptionNode(excel), 77 | getLastModifiedByNode(excel), 78 | getCreatedAtNode(excel), 79 | getModifiedAtNode(excel), 80 | ...getCustomCategoriesNodes(excel), 81 | ] 82 | } 83 | } 84 | }); 85 | 86 | function getTitleNode(excel: JSExcel): ___JSE_XLSX___Node { 87 | return { 88 | name: fileProps.nodes.dcTitle, 89 | content: DEFAULT_PROPS_TITLE 90 | }; 91 | } 92 | 93 | function getSubjectNode(excel: JSExcel): ___JSE_XLSX___Node { 94 | return { 95 | name: fileProps.nodes.dcSubject, 96 | content: DEFAULT_PROPS_SUBJECT 97 | }; 98 | } 99 | 100 | function getCreatorNode(excel: JSExcel): ___JSE_XLSX___Node { 101 | return { 102 | name: fileProps.nodes.dcCreator, 103 | content: DEFAULT_PROPS_CREATOR 104 | }; 105 | } 106 | 107 | function getKeywordsNode(excel: JSExcel): ___JSE_XLSX___Node { 108 | return { 109 | name: fileProps.nodes.dcKeywords, 110 | content: DEFAULT_PROPS_KEYWORDS 111 | }; 112 | } 113 | 114 | function getDescriptionNode(excel: JSExcel): ___JSE_XLSX___Node { 115 | return { 116 | name: fileProps.nodes.dcDescription, 117 | content: DEFAULT_PROPS_DESCRIPTION 118 | }; 119 | } 120 | 121 | function getLastModifiedByNode(excel: JSExcel): ___JSE_XLSX___Node { 122 | return { 123 | name: fileProps.nodes.cpLastModifiedBy, 124 | content: DEFAULT_PROPS_LAST_MODIFIED_BY 125 | }; 126 | } 127 | 128 | function getCreatedAtNode(excel: JSExcel): ___JSE_XLSX___Node { 129 | return { 130 | name: fileProps.node.dcTermsCreated, 131 | values: [{key: fileProps.keys.xsiType, value: fileProps.values.xsiType}], 132 | content: getISOFormattedDate() 133 | }; 134 | } 135 | 136 | function getModifiedAtNode(excel: JSExcel): ___JSE_XLSX___Node { 137 | return { 138 | name: fileProps.node.dcTermsModified, 139 | values: [{key: fileProps.keys.xsiType, value: fileProps.values.xsiType}], 140 | content: getISOFormattedDate() 141 | }; 142 | } 143 | 144 | function getCustomCategoriesNodes(excel: JSExcel): Array<___JSE_XLSX___Node> { 145 | // TODO: Tier-03 Complete when document props interface is finished 146 | return []; 147 | } 148 | -------------------------------------------------------------------------------- /src/xlsx/docProps/FileDocPropsCustom.ts: -------------------------------------------------------------------------------- 1 | // TODO: Tier-02 Replace values when file properties module is implemented 2 | import {JSExcel} from "../../Types"; 3 | import {___JSE_XLSX___File} from "../../api/xlsx"; 4 | import { 5 | DEFAULT_STAND_ALONE, 6 | DEFAULT_XML_VERSION, 7 | ENCODING_UTF_8, 8 | EXTENSION_XML, 9 | FILE_CUSTOM, XMLNS_CUSTOM_PROPERTIES, XMLNS_DOC_PROPS_V_TYPES 10 | } from "../../api/Internals"; 11 | 12 | const fileProps: any = { 13 | xml: { 14 | version: DEFAULT_XML_VERSION, 15 | encoding: ENCODING_UTF_8, 16 | standalone: DEFAULT_STAND_ALONE 17 | }, 18 | name: FILE_CUSTOM, 19 | extension: EXTENSION_XML, 20 | nodes: { 21 | Properties: "Properties", 22 | property: "property", 23 | vtBool: "vt:bool" 24 | }, 25 | keys: { 26 | xmlns: "xmlns", 27 | xmlnsVt: "xmlns:vt", 28 | fmtId: "fmtid", 29 | pid: "pid", 30 | name: "name" 31 | }, 32 | values: { 33 | fmtId: "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", //TODO: Verify encoding 34 | pid: 2, 35 | name: "isDataCompleteCustomField" 36 | } 37 | }; 38 | 39 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 40 | fileName: fileProps.name, 41 | fileExtension: fileProps.extension, 42 | fileContent: { 43 | xml: {...fileProps.xml}, 44 | content: { 45 | name: fileProps.nodes.Properties, 46 | values: [ 47 | {key: fileProps.keys.xmlns, value: XMLNS_CUSTOM_PROPERTIES}, 48 | {key: fileProps.keys.xmlnsVt, value: XMLNS_DOC_PROPS_V_TYPES} 49 | ], 50 | content: { 51 | name: fileProps.nodes.property, 52 | values: [ 53 | {key: fileProps.keys.fmtId, value: fileProps.values.fmtId}, 54 | {key: fileProps.keys.pid, value: fileProps.values.pid}, 55 | {key: fileProps.keys.name, value: fileProps.values.name} 56 | ], 57 | content: { 58 | name: fileProps.nodes.vtBool, 59 | content: true 60 | } 61 | } 62 | } 63 | } 64 | }); 65 | -------------------------------------------------------------------------------- /src/xlsx/xl/DirectoryXl.ts: -------------------------------------------------------------------------------- 1 | import {DIRECTORY_DOC_PROPS} from "../../api/Internals"; 2 | import {JSExcel} from "../../Types"; 3 | import {___JSE_XLSX___Directory, ___JSE_XLSX___File} from "../../api/xlsx"; 4 | import appFile from "../docProps/FileDocPropsApp"; 5 | import coreFile from "../docProps/FileDocPropsCore"; 6 | import customFile from "../docProps/FileDocPropsCustom"; 7 | 8 | const directoryProps: any = { 9 | name: DIRECTORY_DOC_PROPS 10 | }; 11 | 12 | export default (excel: JSExcel): ___JSE_XLSX___Directory => ({ 13 | directoryName: directoryProps.name, 14 | content: getRelDirectoryFiles(excel) 15 | }); 16 | 17 | function getRelDirectoryFiles(excel: JSExcel): Array<___JSE_XLSX___File> { 18 | return [appFile(excel), coreFile(excel), customFile(excel)]; 19 | } -------------------------------------------------------------------------------- /src/xlsx/xl/FileSharedStrings.ts: -------------------------------------------------------------------------------- 1 | import {JSECell, JSEData, JSERow, JSESheet, JSExcel} from "../../Types"; 2 | import {___JSE_XLSX___File, ___JSE_XLSX___Node} from "../../api/xlsx"; 3 | import { 4 | DEFAULT_STAND_ALONE, 5 | DEFAULT_XML_VERSION, 6 | ENCODING_UTF_8, 7 | EXTENSION_XML, 8 | FILE_SHARED_STRINGS, 9 | XMLNS_SST 10 | } from "../../api/Internals"; 11 | import {excelTotalCellCounter} from "../../util/ExcelUtil"; 12 | 13 | 14 | const fileProps: any = { 15 | xml: { 16 | version: DEFAULT_XML_VERSION, 17 | encoding: ENCODING_UTF_8, 18 | standalone: DEFAULT_STAND_ALONE 19 | }, 20 | name: FILE_SHARED_STRINGS, 21 | extension: EXTENSION_XML, 22 | nodes: { 23 | sst: "sst", 24 | si: "si", 25 | t: "t" 26 | }, 27 | keys: { 28 | xmlns: "xmlns", 29 | count: "count", 30 | uniqueCount: "uniqueCount" 31 | } 32 | }; 33 | 34 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 35 | fileName: fileProps.name, 36 | fileExtension: fileProps.extension, 37 | fileContent: { 38 | xml: {...fileProps.xml}, 39 | content: { 40 | name: fileProps.nodes.sst, 41 | values: [ 42 | {key: fileProps.keys.xmlns, value: XMLNS_SST}, 43 | {key: fileProps.keys.count, value: getCounts(excel)}, 44 | {key: fileProps.keys.uniqueCount, value: getCounts(excel)}, 45 | ], 46 | content: getCellContentsFromExcel(excel) 47 | } 48 | } 49 | }); 50 | 51 | function getCellContentsFromExcel(excel: JSExcel): Array<___JSE_XLSX___Node> { 52 | return excel.sheets.flatMap(getCellContentsFromSheet).map(getCellNode); 53 | } 54 | 55 | function getCellContentsFromSheet(sheet: JSESheet): Array { 56 | if (sheet == null || sheet == undefined) return []; 57 | const {columns, data} = sheet; 58 | const colArr: Array = columns ? columns : []; 59 | const dataArr: Array = data ? getCellContentsFromData(data) : []; 60 | 61 | return colArr.concat(dataArr); 62 | } 63 | 64 | function getCellContentsFromData(data: JSEData): Array { 65 | if (data == null || data == undefined) return []; 66 | 67 | return data.flatMap(getRowContent); 68 | } 69 | 70 | function getRowContent(row: JSERow): Array { 71 | return row.map(item => item); 72 | } 73 | 74 | function getCellNode(cell: JSECell): ___JSE_XLSX___Node { 75 | return { 76 | name: fileProps.nodes.si, 77 | content: { 78 | name: fileProps.node.t, 79 | content: cell.content 80 | } 81 | }; 82 | } 83 | 84 | function getCounts(excel: JSExcel): number { 85 | // TODO: Add separate flag to count uniqueCount 86 | return excelTotalCellCounter(excel); 87 | } 88 | -------------------------------------------------------------------------------- /src/xlsx/xl/FileStyles.ts: -------------------------------------------------------------------------------- 1 | import {DEFAULT_FONT_SIZE, DEFAULT_FONT_NAME, DEFAULT_FONT_COLOR} from "../../api/constants"; 2 | import { 3 | DEFAULT_STAND_ALONE, 4 | DEFAULT_XML_VERSION, 5 | ENCODING_UTF_8, 6 | EXTENSION_XML, 7 | FILE_STYLES, XMLNS_MAIN, XMLNS_MC, XMLNS_X14AC, XMLNS_X16R2, XMLNS_XR 8 | } from "../../api/Internals"; 9 | import {___JSE_XLSX___File, ___JSE_XLSX___Node} from "../../api/xlsx"; 10 | import {JSEFont, JSExcel, JSEColor, JSECellBorder, JSEBorderType} from "../../Types"; 11 | import {extractFontsFromExcel, hasFontsInExcel, hasBordersInExcel, extractBordersFromExcel} from "../../util/ExcelUtil"; 12 | 13 | const fileProps: any = { 14 | xml: { 15 | version: DEFAULT_XML_VERSION, 16 | encoding: ENCODING_UTF_8, 17 | standalone: DEFAULT_STAND_ALONE 18 | }, 19 | name: FILE_STYLES, 20 | extension: EXTENSION_XML, 21 | nodes: { 22 | styleSheet: "styleSheet", 23 | fonts: "fonts", 24 | font: "font", 25 | sz: "sz", 26 | color: "color", 27 | name: "name", 28 | b: "b", 29 | i: "i", 30 | u: "u", 31 | family: "family", 32 | fills: "fills", 33 | fill: "fill", 34 | patternFill: "patternFill", 35 | fgColor: "fgColor", 36 | bgColor: "bgColor", 37 | borders: "borders", 38 | border: "border", 39 | left: "left", 40 | right: "right", 41 | top: "top", 42 | bottom: "bottom", 43 | diagonal: "diagonal", 44 | cellStyleXfs: "cellStyleXfs", 45 | cellXfs: "cellXfs", 46 | xf: "xf", 47 | alignment: "alignment", 48 | cellStyles: "cellStyles", 49 | cellStyle: "cellStyle", 50 | dxfs: "dxfs", 51 | tableStyles: "tableStyles", 52 | extLst: "extLst", 53 | ext: "ext", 54 | x14SlicerStyles: "x14:slicerStyles", 55 | x15TimelineStyles: "x15:timelineStyles" 56 | }, 57 | keys: { 58 | val: "val", 59 | rgb: "rgb", 60 | theme: "theme", 61 | tint: "tint", 62 | count: "count", 63 | patternType: "patternType", 64 | indexed: "indexed", 65 | style: "style", 66 | numFmtId: "numFmtId", 67 | fontId: "fontId", 68 | fillId: "fillId", 69 | borderId: "borderId", 70 | xfId: "xfId", 71 | applyFont: "applyFont", 72 | applyFill: "applyFill", 73 | applyBorder: "applyBorder", 74 | applyAlignment: "applyAlignment", 75 | horizontal: "horizontal", 76 | vertical: "vertical", 77 | name: "name", 78 | builtinId: "builtinId", 79 | defaultTableStyle: "defaultTableStyle", 80 | defaultPivotStyle: "defaultPivotStyle", 81 | uri: "uri", 82 | xmlnsX14: "xmlns:x14", 83 | xmlnsX15: "xmlns:x15", 84 | xmlns: "xmlns", 85 | xmlnsMc: "xmlns:mc", 86 | mcIgnorable: "mc:Ignorable", 87 | xmlnsX14ac: "xmlns:x14ac", 88 | xmlnsX16r2: "xmlns:x16r2", 89 | xmlnsXr: "xmlns:xr", 90 | defaultSlicerStyle: "defaultSlicerStyle", 91 | defaultTimelineStyle: "defaultTimelineStyle" 92 | }, 93 | }; 94 | 95 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 96 | fileName: fileProps.name, 97 | fileExtension: fileProps.extension, 98 | fileContent: { 99 | xml: {...fileProps.xml}, 100 | content: { 101 | name: fileProps.nodes.styleSheet, 102 | values: [ 103 | {key: fileProps.keys.xmlns, value: XMLNS_MAIN}, 104 | {key: fileProps.keys.xmlnsMc, value: XMLNS_MC}, 105 | {key: fileProps.keys.mcIgnorable, value: "x14ac x16r2 xr"}, //TODO: Double check 106 | {key: fileProps.keys.xmlnsX14ac, value: XMLNS_X14AC}, 107 | {key: fileProps.keys.xmlnsX16r2, value: XMLNS_X16R2}, 108 | {key: fileProps.keys.xmlnsXr, value: XMLNS_XR} 109 | ], 110 | content: [ 111 | getFontsNodes(excel), 112 | // getFillsNodes(excel), 113 | getBorderNodes(excel), 114 | getCellStyleXfsNodes(excel), 115 | getCellXfsNodes(excel), 116 | getCellStylesNodes(excel), 117 | getDXFSNodes(excel), 118 | getTableStylesNodes(excel), 119 | getExtLstNodes(excel) 120 | ] 121 | } 122 | } 123 | }); 124 | 125 | function getFontsNodes(excel: JSExcel): ___JSE_XLSX___Node | undefined { 126 | if (hasFontsInExcel(excel)) { 127 | return { 128 | name: fileProps.nodes.fonts, 129 | content: extractFonts(excel) 130 | }; 131 | } 132 | } 133 | 134 | function extractFonts(excel: JSExcel): Array<___JSE_XLSX___Node> { 135 | return extractFontsFromExcel(excel).map(getFontNode); 136 | } 137 | 138 | function getFontNode(font: JSEFont): ___JSE_XLSX___Node { 139 | const fontCalculatedNodes: Array<___JSE_XLSX___Node | undefined> = [ 140 | getFontProperty_Bold(font), 141 | getFontProperty_Italic(font), 142 | getFontProperty_Underline(font), 143 | getFontProperty_Size(font), 144 | getFontProperty_Color(font), 145 | getFontProperty_Name(font), 146 | getFontProperty_Family(font) 147 | ]; 148 | 149 | const fontNodes: Array<___JSE_XLSX___Node> = []; 150 | 151 | fontCalculatedNodes.forEach((item: ___JSE_XLSX___Node | undefined) => { 152 | if (item !== null || item !== undefined) { 153 | fontNodes.push(item as ___JSE_XLSX___Node); 154 | } 155 | }); 156 | 157 | return { 158 | name: fileProps.nodes.font, 159 | content: fontNodes 160 | }; 161 | } 162 | 163 | function getFontProperty_Bold(font: JSEFont): ___JSE_XLSX___Node | undefined { 164 | if (!font.bold) { 165 | return; 166 | } 167 | 168 | return { 169 | name: fileProps.nodes.b 170 | }; 171 | } 172 | 173 | function getFontProperty_Italic(font: JSEFont): ___JSE_XLSX___Node | undefined { 174 | if (!font.italic) { 175 | return; 176 | } 177 | 178 | return { 179 | name: fileProps.nodes.i 180 | }; 181 | } 182 | 183 | function getFontProperty_Underline(font: JSEFont): ___JSE_XLSX___Node | undefined { 184 | if (!font.underline) { 185 | return; 186 | } 187 | 188 | return { 189 | name: fileProps.nodes.u 190 | }; 191 | } 192 | 193 | function getFontProperty_Size(font: JSEFont): ___JSE_XLSX___Node { 194 | const fontSize: number = !font.size ? DEFAULT_FONT_SIZE : font.size; 195 | 196 | return { 197 | name: fileProps.nodes.sz, 198 | values: [{key: fileProps.keys.val, value: fontSize}] 199 | }; 200 | } 201 | 202 | function getFontProperty_Color(font: JSEFont): ___JSE_XLSX___Node { 203 | let fontColor: string; 204 | let theme: any; 205 | let tint: any; 206 | 207 | if (!font.color) { 208 | fontColor = DEFAULT_FONT_COLOR; 209 | } 210 | 211 | if (typeof font.color === "string") { 212 | fontColor = font.color; 213 | } else { 214 | const colour: JSEColor = font.color as JSEColor; 215 | fontColor = !colour.rgb ? DEFAULT_FONT_COLOR : colour.rgb; 216 | 217 | if (colour.theme) { 218 | theme = {key: fileProps.keys.theme, value: colour.theme}; 219 | } 220 | 221 | if (colour.tint) { 222 | tint = {key: fileProps.keys.tint, value: colour.tint}; 223 | } 224 | } 225 | 226 | return { 227 | name: fileProps.nodes.color, 228 | values: [ 229 | {key: fileProps.keys.rgb, value: fontColor}, 230 | ...theme, 231 | ...tint 232 | ] 233 | }; 234 | } 235 | 236 | function getFontProperty_Name(font: JSEFont): ___JSE_XLSX___Node { 237 | const fontName: string = !font.name ? DEFAULT_FONT_NAME : font.name; 238 | 239 | return { 240 | name: fileProps.nodes.name, 241 | values: [{key: fileProps.keys.val, value: fontName}] 242 | }; 243 | } 244 | 245 | function getFontProperty_Family(font: JSEFont): ___JSE_XLSX___Node | undefined { 246 | if (!font.family) { 247 | return; 248 | } 249 | 250 | return { 251 | name: fileProps.nodes.family, 252 | values: [{key: fileProps.keys.val, value: font.family}] 253 | }; 254 | } 255 | 256 | /*function getFillsNodes(excel: JSExcel): ___JSE_XLSX___Node { 257 | if (hasFillsInExcel(excel)) { 258 | return { 259 | name: fileProps.nodes.fills, 260 | content: extractFills(excel) 261 | }; 262 | } 263 | }*/ 264 | 265 | function getBorderNodes(excel: JSExcel): ___JSE_XLSX___Node | undefined { 266 | if (hasBordersInExcel(excel)) { 267 | const borders: Array = extractBordersFromExcel(excel); 268 | 269 | return { 270 | name: fileProps.nodes.borders, 271 | values: [{key: fileProps.keys.count, value: borders.length}], 272 | content: borders.map(getBorderNode) 273 | }; 274 | } 275 | } 276 | 277 | function getBorderNode(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 278 | return { 279 | name: fileProps.nodes.border, 280 | content: [ 281 | getLeftCellBorder(border), 282 | getRightCellBorder(border), 283 | getTopCellBorder(border), 284 | getBottomCellBorder(border), 285 | getDiagonalCellBorder(border), 286 | ] 287 | }; 288 | } 289 | 290 | function getLeftCellBorder(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 291 | if (!border.left) { 292 | return; 293 | } 294 | 295 | const style: JSEBorderType = border.left.type || "thin"; 296 | let colorIndex: any; 297 | 298 | if (border.left.color) { 299 | colorIndex = { 300 | content: [{ 301 | name: fileProps.nodes.color, 302 | values: [ 303 | {key: fileProps.keys.indexed, value: border.left.color} 304 | ] 305 | }] 306 | }; 307 | } 308 | 309 | return { 310 | name: fileProps.nodes.left, 311 | values: [ 312 | {key: fileProps.keys.style, value: style} 313 | ], 314 | ...colorIndex 315 | }; 316 | } 317 | 318 | function getRightCellBorder(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 319 | if (!border.right) { 320 | return; 321 | } 322 | 323 | const style: JSEBorderType = border.right.type || "thin"; 324 | let colorIndex: any; 325 | 326 | if (border.right.color) { 327 | colorIndex = { 328 | content: [{ 329 | name: fileProps.nodes.color, 330 | values: [ 331 | {key: fileProps.keys.indexed, value: border.right.color} 332 | ] 333 | }] 334 | }; 335 | } 336 | 337 | return { 338 | name: fileProps.nodes.right, 339 | values: [ 340 | {key: fileProps.keys.style, value: style} 341 | ], 342 | ...colorIndex 343 | }; 344 | } 345 | 346 | function getTopCellBorder(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 347 | if (!border.top) { 348 | return; 349 | } 350 | 351 | const style: JSEBorderType = border.top.type || "thin"; 352 | let colorIndex: any; 353 | 354 | if (border.top.color) { 355 | colorIndex = { 356 | content: [{ 357 | name: fileProps.nodes.color, 358 | values: [ 359 | {key: fileProps.keys.indexed, value: border.top.color} 360 | ] 361 | }] 362 | }; 363 | } 364 | 365 | return { 366 | name: fileProps.nodes.top, 367 | values: [ 368 | {key: fileProps.keys.style, value: style} 369 | ], 370 | ...colorIndex 371 | }; 372 | } 373 | 374 | function getBottomCellBorder(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 375 | if (!border.bottom) { 376 | return; 377 | } 378 | 379 | const style: JSEBorderType = border.bottom.type || "thin"; 380 | let colorIndex: any; 381 | 382 | if (border.bottom.color) { 383 | colorIndex = { 384 | content: [{ 385 | name: fileProps.nodes.color, 386 | values: [ 387 | {key: fileProps.keys.indexed, value: border.bottom.color} 388 | ] 389 | }] 390 | }; 391 | } 392 | 393 | return { 394 | name: fileProps.nodes.bottom, 395 | values: [ 396 | {key: fileProps.keys.style, value: style} 397 | ], 398 | ...colorIndex 399 | }; 400 | } 401 | 402 | function getDiagonalCellBorder(border: JSECellBorder): ___JSE_XLSX___Node | undefined { 403 | if (!border.diagonal) { 404 | return; 405 | } 406 | 407 | const style: JSEBorderType = border.diagonal.type || "thin"; 408 | let colorIndex: any; 409 | 410 | if (border.diagonal.color) { 411 | colorIndex = { 412 | content: [{ 413 | name: fileProps.nodes.color, 414 | values: [ 415 | {key: fileProps.keys.indexed, value: border.diagonal.color} 416 | ] 417 | }] 418 | }; 419 | } 420 | 421 | return { 422 | name: fileProps.nodes.diagonal, 423 | values: [ 424 | {key: fileProps.keys.style, value: style} 425 | ], 426 | ...colorIndex 427 | }; 428 | } 429 | 430 | function getCellStyleXfsNodes(excel: JSExcel): ___JSE_XLSX___Node { 431 | // TODO: complete as with excel sheet -CODE02 432 | return { 433 | name: fileProps.nodes.cellStyleXfs, 434 | values: [ 435 | {key: fileProps.keys.count, value: "1"} 436 | ], 437 | content: { 438 | name: fileProps.nodes.xf, 439 | values: [ 440 | {key: fileProps.keys.numFmtId, value: "0"}, 441 | {key: fileProps.keys.fontId, value: "0"}, 442 | {key: fileProps.keys.fillId, value: "0"}, 443 | {key: fileProps.keys.borderId, value: "0"} 444 | ] 445 | } 446 | }; 447 | } 448 | 449 | function getCellXfsNodes(excel: JSExcel): ___JSE_XLSX___Node { 450 | // TODO: complete as with excel sheet -CODE02 451 | return { 452 | name: fileProps.nodes.cellXfs, 453 | values: [ 454 | {key: fileProps.keys.count, value: "1"} 455 | ], 456 | content: { 457 | name: fileProps.nodes.xf, 458 | values: [ 459 | {key: fileProps.keys.numFmtId, value: "0"}, 460 | {key: fileProps.keys.fontId, value: "0"}, 461 | {key: fileProps.keys.fillId, value: "0"}, 462 | {key: fileProps.keys.borderId, value: "0"}, 463 | {key: fileProps.keys.xfId, value: "0"} 464 | ] 465 | } 466 | }; 467 | } 468 | 469 | function getCellStylesNodes(excel: JSExcel): ___JSE_XLSX___Node { 470 | // TODO: complete as with excel sheet -CODE02 471 | return { 472 | name: fileProps.nodes.cellStyles, 473 | values: [ 474 | {key: fileProps.keys.count, value: "1"} 475 | ], 476 | content: { 477 | name: fileProps.nodes.cellStyle, 478 | values: [ 479 | {key: fileProps.keys.name, value: "Standard"}, 480 | {key: fileProps.keys.xfId, value: "0"}, 481 | {key: fileProps.keys.builtinId, value: "0"} 482 | ] 483 | } 484 | }; 485 | } 486 | 487 | function getDXFSNodes(excel: JSExcel): ___JSE_XLSX___Node { 488 | // TODO: complete as with excel sheet -CODE02 489 | return { 490 | name: fileProps.nodes.dxfs, 491 | values: [ 492 | {key: fileProps.keys.count, value: "0"} 493 | ] 494 | }; 495 | } 496 | 497 | function getTableStylesNodes(excel: JSExcel): ___JSE_XLSX___Node { 498 | // TODO: complete as with excel sheet -CODE02 499 | return { 500 | name: fileProps.nodes.tableStyles, 501 | values: [ 502 | {key: fileProps.keys.count, value: "0"}, 503 | {key: fileProps.keys.defaultTableStyle, value: "TableStyleMedium2"}, 504 | {key: fileProps.keys.defaultPivotStyle, value: "PivotStyleMedium9"} 505 | ] 506 | }; 507 | } 508 | 509 | function getExtLstNodes(excel: JSExcel): ___JSE_XLSX___Node { 510 | // TODO: complete as with excel sheet -CODE02 511 | return { 512 | name: fileProps.nodes.extLst, 513 | content: [ 514 | { 515 | name: fileProps.nodes.ext, 516 | values: [ 517 | {key: fileProps.keys.uri, value: "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"}, 518 | { 519 | key: fileProps.keys.xmlnsX14, 520 | value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" 521 | } 522 | ], 523 | content: { 524 | name: fileProps.nodes.x14SlicerStyles, 525 | values: [ 526 | {key: fileProps.keys.defaultSlicerStyle, value: "SlicerStyleLight1"} 527 | ] 528 | } 529 | }, 530 | { 531 | name: fileProps.nodes.ext, 532 | values: [ 533 | {key: fileProps.keys.uri, value: "{9260A510-F301-46a8-8635-F512D64BE5F5}"}, 534 | { 535 | key: fileProps.keys.xmlnsX14, 536 | value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" 537 | } 538 | ], 539 | content: { 540 | name: fileProps.nodes.x15TimelineStyles, 541 | values: [ 542 | {key: fileProps.keys.defaultTimelineStyle, value: "SlicerStyleLight1"} 543 | ] 544 | } 545 | } 546 | ] 547 | }; 548 | } 549 | -------------------------------------------------------------------------------- /src/xlsx/xl/FileWorkbook.ts: -------------------------------------------------------------------------------- 1 | import {JSESheet, JSExcel} from "../../Types"; 2 | import {___JSE_XLSX___File, ___JSE_XLSX___Node} from "../../api/xlsx"; 3 | import { 4 | DEFAULT_STAND_ALONE, 5 | DEFAULT_XML_VERSION, 6 | ENCODING_UTF_8, 7 | EXTENSION_XML, 8 | FILE_WORKBOOK, 9 | XMLNS_MAIN, 10 | XMLNS_MC, 11 | XMLNS_OFFICE_DOCUMENT_RELATIONSHIPS, 12 | XMLNS_XR 13 | } from "../../api/Internals"; 14 | 15 | const fileProps: any = { 16 | xml: { 17 | version: DEFAULT_XML_VERSION, 18 | encoding: ENCODING_UTF_8, 19 | standalone: DEFAULT_STAND_ALONE 20 | }, 21 | name: FILE_WORKBOOK, 22 | extension: EXTENSION_XML, 23 | nodes: { 24 | workbook: "workbook", 25 | fileVersion: "fileVersion", 26 | workbookPr: "workbookPr", 27 | xrRevisionPtr: "xr:revisionPtr", 28 | bookViews: "bookViews", 29 | workbookView: "workbookView", 30 | sheets: "sheets", 31 | sheet: "sheet", 32 | calcPr: "calcPr", 33 | extLst: "extLst", 34 | ext: "ext", 35 | xcalcfCalcFeatures: "xcalcf:calcFeatures", 36 | xcalcfFeature: "xcalcf:feature" 37 | }, 38 | keys: { 39 | xmlns: "xmlns", 40 | xmlnsR: "xmlns:r", 41 | xmlnsMC: "xmlns:mc", 42 | xmlnsX15: "xmlns:x15", 43 | xmlnsXR: "xmlns:xr", 44 | xmlnsXR6: "xmlns:xr6", 45 | xmlnsXR10: "xmlns:xr10", 46 | xmlnsXR2: "xmlns:xr2", 47 | mcIgnorable: "mc:Ignorable", 48 | appName: "appName", 49 | lastEdited: "lastEdited", 50 | lowestEdited: "lowestEdited", 51 | rupBuild: "rupBuild", 52 | defaultThemeVersion: "defaultThemeVersion", 53 | revIDLastSave: "revIDLastSave", 54 | documentId: "documentId", 55 | xr6CoauthVersionLast: "xr6:coauthVersionLast", 56 | xr6CoauthVersionMax: "xr6:coauthVersionMax", 57 | xr10UidLastSave: "xr10:uidLastSave", 58 | xWindow: "xWindow", 59 | yWindow: "yWindow", 60 | windowWidth: "windowWidth", 61 | windowHeight: "windowHeight", 62 | activeTab: "activeTab", 63 | xr2Uid: "xr2:uid", 64 | name: "name", 65 | sheetId: "sheetId", 66 | rId: "r:id", 67 | calcId: "calcId", 68 | uri: "uri", 69 | xmlnsXcalcf: "xmlns:xcalcf" 70 | } 71 | }; 72 | 73 | export default (excel: JSExcel): ___JSE_XLSX___File => ({ 74 | fileName: fileProps.name, 75 | fileExtension: fileProps.extension, 76 | fileContent: { 77 | xml: {...fileProps.xml}, 78 | content: { 79 | name: fileProps.nodes.workbook, 80 | values: [ 81 | {key: fileProps.keys.xmlns, value: XMLNS_MAIN}, 82 | {key: fileProps.keys.xmlnsR, value: XMLNS_OFFICE_DOCUMENT_RELATIONSHIPS}, 83 | {key: fileProps.keys.xmlnsMC, value: XMLNS_MC}, 84 | {key: fileProps.keys.mcIgnorable, value: "x15 xr xr6 xr10 xr2"}, 85 | {key: fileProps.keys.xmlnsX15, value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}, 86 | {key: fileProps.keys.xmlnsXR, value: XMLNS_XR}, 87 | { 88 | key: fileProps.keys.xmlnsXR6, 89 | value: "http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" 90 | }, 91 | { 92 | key: fileProps.keys.xmlnsXR10, 93 | value: "http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" 94 | }, 95 | { 96 | key: fileProps.keys.xmlnsXR2, 97 | value: "http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" 98 | }, 99 | ], 100 | content: getWorkbookContents(excel) 101 | } 102 | } 103 | }); 104 | 105 | function getWorkbookContents(excel: JSExcel): Array<___JSE_XLSX___Node> { 106 | return [ 107 | getFileVersionNode(excel), 108 | getWorkbookPrNode(excel), 109 | getXRRevisionPtrNode(excel), 110 | getBookViewsNode(excel), 111 | getSheetsNode(excel), 112 | getCalcPrNode(excel), 113 | getExtLstNode(excel) 114 | ]; 115 | } 116 | 117 | function getFileVersionNode(excel: JSExcel): ___JSE_XLSX___Node { 118 | return { 119 | name: fileProps.nodes.fileVersion, 120 | values: [ 121 | {key: fileProps.keys.appName, value: "xl"}, 122 | {key: fileProps.keys.lastEdited, value: "7"}, // TODO: verify again 123 | {key: fileProps.keys.lowestEdited, value: "4"}, 124 | {key: fileProps.keys.rupBuild, value: "21230"} 125 | ] 126 | }; 127 | } 128 | 129 | function getWorkbookPrNode(excel: JSExcel): ___JSE_XLSX___Node { 130 | return { 131 | name: fileProps.nodes.workbookPr, 132 | values: [ 133 | {key: fileProps.keys.defaultThemeVersion, value: "166925"} //TODO: Verify value and create a constant 134 | ] 135 | }; 136 | } 137 | 138 | function getXRRevisionPtrNode(excel: JSExcel): ___JSE_XLSX___Node { 139 | return { 140 | name: fileProps.nodes.xrRevisionPtr, 141 | values: [ 142 | {key: fileProps.keys.revIDLastSave, value: "0"}, 143 | {key: fileProps.keys.documentId, value: "8_{73AD8C06-8AEC-4845-8D70-B34A27716D4F}"}, 144 | {key: fileProps.keys.xr6CoauthVersionLast, value: "40"}, 145 | {key: fileProps.keys.xr6CoauthVersionMax, value: "40"}, 146 | {key: fileProps.keys.xr10UidLastSave, value: "{00000000-0000-0000-0000-000000000000}"} 147 | ] 148 | }; 149 | } 150 | 151 | function getBookViewsNode(excel: JSExcel): ___JSE_XLSX___Node { 152 | return { 153 | name: fileProps.nodes.bookViews, 154 | content: [ 155 | { 156 | name: fileProps.nodes.workbookView, 157 | values: [ 158 | {key: fileProps.keys.xWindow, value: "240"}, 159 | {key: fileProps.keys.yWindow, value: "105"}, 160 | {key: fileProps.keys.windowWidth, value: "14805"}, 161 | {key: fileProps.keys.windowHeight, value: "8010"}, 162 | {key: fileProps.keys.activeTab, value: "1"}, 163 | {key: fileProps.keys.activeTab, value: "1"}, 164 | {key: fileProps.keys.xr2Uid, value: "{00000000-000D-0000-FFFF-FFFF00000000}"} 165 | ] 166 | } 167 | ] 168 | }; 169 | } 170 | 171 | function getSheetsNode(excel: JSExcel): ___JSE_XLSX___Node { 172 | return { 173 | name: fileProps.nodes.sheets, 174 | content: excel.sheets.map(getSheetNode) 175 | }; 176 | } 177 | 178 | function getSheetNode(sheet: JSESheet, index: number): ___JSE_XLSX___Node { 179 | return { 180 | name: fileProps.nodes.sheet, 181 | values: [ 182 | {key: fileProps.keys.name, value: sheet.name}, 183 | {key: fileProps.keys.id, value: `${index + 1}`}, 184 | {key: fileProps.keys.rId, value: `rId${index + 1}`} 185 | ] 186 | }; 187 | } 188 | 189 | function getCalcPrNode(excel: JSExcel): ___JSE_XLSX___Node { 190 | return { 191 | name: fileProps.nodes.calcPr, 192 | values: [ 193 | {key: fileProps.keys.calcId, value: "191028"} 194 | ] 195 | }; 196 | } 197 | 198 | function getExtLstNode(excel: JSExcel): ___JSE_XLSX___Node { 199 | return { 200 | name: fileProps.nodes.extLst, 201 | content: { 202 | name: fileProps.nodes.ext, 203 | values: [ 204 | {key: fileProps.keys.uri, value: "{B58B0392-4F1F-4190-BB64-5DF3571DCE5F}"}, 205 | { 206 | key: fileProps.keys.xmlnsXcalcf, 207 | value: "http://schemas.microsoft.com/office/spreadsheetml/2018/calcfeatures" 208 | } 209 | ], 210 | content: { 211 | name: fileProps.nodes.xcalcfCalcFeatures, 212 | content: { 213 | name: fileProps.nodes.xcalcfFeature, 214 | values: [ 215 | {key: fileProps.keys.name, value: "microsoft.com:RD"} 216 | ] 217 | } 218 | } 219 | } 220 | }; 221 | } 222 | -------------------------------------------------------------------------------- /src/xlsx/xl/_rels/DirectoryRels.ts: -------------------------------------------------------------------------------- 1 | import { 2 | XMLNS_RELATIONSHIPS, 3 | EXTENSION_RELS, 4 | DEFAULT_XML_VERSION, 5 | ENCODING_UTF_8, 6 | DEFAULT_STAND_ALONE, FILE_RELS 7 | } from "../../../api/Internals"; 8 | import {EXTENSION_XML, FILE_WORKBOOK} from "../../../api/Internals"; 9 | import {JSESheet, JSExcel} from "../../../Types"; 10 | import { 11 | ___JSE_XLSX___Directory, 12 | ___JSE_XLSX___File, 13 | ___JSE_XLSX___FileContent, 14 | ___JSE_XLSX___Node 15 | } from "../../../api/xlsx"; 16 | 17 | const fileProps: any = { 18 | name: `${FILE_WORKBOOK}${EXTENSION_XML}`, 19 | extension: EXTENSION_RELS, 20 | version: DEFAULT_XML_VERSION, 21 | encoding: ENCODING_UTF_8, 22 | standalone: DEFAULT_STAND_ALONE, 23 | nodes: { 24 | Relationships: "Relationships", 25 | Relationship: "Relationship" 26 | }, 27 | keys: { 28 | xmlns: "xmlns", 29 | Id: "Id", 30 | Type: "Type", 31 | Target: "Target" 32 | } 33 | }; 34 | 35 | const directorProps: any = { 36 | name: FILE_RELS, 37 | files: {workBookXMLRels: {...fileProps}} 38 | }; 39 | 40 | export default (excel: JSExcel): ___JSE_XLSX___Directory => ({ 41 | directoryName: directorProps.name, 42 | content: getRelDirectoryFiles(excel) 43 | }); 44 | 45 | function getRelDirectoryFiles(excel: JSExcel): ___JSE_XLSX___File { 46 | return { 47 | fileName: fileProps.name, 48 | fileExtension: fileProps.extension, 49 | fileContent: getRelsNodes(excel) 50 | }; 51 | } 52 | 53 | function getRelsNodes(excel: JSExcel): ___JSE_XLSX___FileContent { 54 | return { 55 | xml: { 56 | version: fileProps.version, 57 | encoding: fileProps.encoding, 58 | standalone: fileProps.standalone 59 | }, 60 | content: { 61 | name: fileProps.nodes.Relationships, 62 | values: [{key: fileProps.keys.xmlns, value: XMLNS_RELATIONSHIPS}], 63 | content: [ 64 | ...excel.sheets.map((sheet: JSESheet, index: number): ___JSE_XLSX___Node => { 65 | return { 66 | name: fileProps.nodes.Relationship, 67 | values: [ 68 | {key: fileProps.keys.Id, value: `rId${index + 1}`}, 69 | { 70 | key: fileProps.keys.Type, 71 | value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" 72 | }, 73 | {key: fileProps.keys.Target, value: `worksheets/sheet${index + 1}.xml`} 74 | ] 75 | }; 76 | }), 77 | { 78 | name: fileProps.nodes.Relationship, 79 | values: [ 80 | {key: fileProps.keys.Id, value: `rId${excel.sheets.length + 1}`}, 81 | { 82 | key: fileProps.keys.Type, 83 | value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" 84 | }, 85 | {key: fileProps.keys.Target, value: "theme/theme1.xml"} 86 | ] 87 | }, 88 | { 89 | name: fileProps.nodes.Relationship, 90 | values: [ 91 | {key: fileProps.keys.Id, value: `rId${excel.sheets.length + 2}`}, 92 | { 93 | key: fileProps.keys.Type, 94 | value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" 95 | }, 96 | {key: fileProps.keys.Target, value: "sharedStrings.xml"} 97 | ] 98 | }, 99 | { 100 | name: fileProps.nodes.Relationship, 101 | values: [ 102 | {key: fileProps.keys.Id, value: `rId${excel.sheets.length + 3}`}, 103 | { 104 | key: fileProps.keys.Type, 105 | value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" 106 | }, 107 | {key: fileProps.keys.Target, value: "styles.xml"} 108 | ] 109 | } 110 | ] 111 | } 112 | }; 113 | } 114 | -------------------------------------------------------------------------------- /src/xlsx/xl/theme/FileTheme1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedeveloper/javascript-excel/c93af21edf7e881e153e689186319e9ea01a88e1/src/xlsx/xl/theme/FileTheme1.ts -------------------------------------------------------------------------------- /src/xlsx/xl/worksheets/FileWorksheet.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securedeveloper/javascript-excel/c93af21edf7e881e153e689186319e9ea01a88e1/src/xlsx/xl/worksheets/FileWorksheet.ts -------------------------------------------------------------------------------- /test/unit/Helper.test.ts: -------------------------------------------------------------------------------- 1 | import {cleanAlphaNumericString, getISOFormattedDate} from "../../src/util/Helper"; 2 | 3 | describe("Helper --> ", () => { 4 | describe("String -->", () => { 5 | test("it return a clean expected string", () => { 6 | const inputs: Array = ["\\test\red\bob\fred\new", "±~NaNNumericApha$-and_returned0"]; 7 | const outputs: Array = ["testedobredew", "NaNNumericAphaand_returned0"]; 8 | 9 | inputs.forEach((input: string, index: number) => { 10 | expect(cleanAlphaNumericString(input)).toBe(outputs[index]); 11 | }); 12 | }); 13 | 14 | test("it return exact input if wrong string value is supplied", () => { 15 | const inputs: Array = [false, undefined, true, 121, new Date(), {}, null]; 16 | 17 | inputs.forEach((input: any) => { 18 | expect(cleanAlphaNumericString(input)).toBe(input); 19 | }); 20 | }); 21 | }); 22 | 23 | describe("Date -->", () => { 24 | test("it should return required ISO formatted date stamp w.r.t date provided", () => { 25 | const inputDate: Date = new Date('05 October 2011 14:48 UTC'); 26 | const expectedOutput: string = "2011-10-05T14:48:00Z"; 27 | 28 | expect(getISOFormattedDate(inputDate)).toBe(expectedOutput); 29 | }); 30 | 31 | 32 | test("it should return today as ISO formatted date stamp if no arg is provided", () => { 33 | const expectedOutput: string = new Date().toISOString().split(".")[0] + "Z"; 34 | 35 | expect(getISOFormattedDate()).toBe(expectedOutput); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "esnext", 5 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 6 | "module": "commonjs", 7 | /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 8 | // "lib": [], /* Specify library files to be included in the compilation: */ 9 | // "allowJs": true, /* Allow javascript files to be compiled. */ 10 | // "checkJs": true, /* Report errors in .js files. */ 11 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 12 | "declaration": true, 13 | /* Generates corresponding '.d.ts' file. */ 14 | "sourceMap": true, 15 | /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "lib", 18 | /* Redirect output structure to the directory. */ 19 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 20 | // "removeComments": true, /* Do not emit comments to output. */ 21 | // "noEmit": true, /* Do not emit outputs. */ 22 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 23 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 24 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 25 | 26 | /* Strict Type-Checking Options */ 27 | "strict": true, 28 | /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 32 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 33 | 34 | /* Additional Checks */ 35 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 36 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 37 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 38 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 39 | 40 | /* Module Resolution Options */ 41 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 42 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 43 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 44 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 45 | // "typeRoots": [], /* List of folders to include type definitions from. */ 46 | // "types": [], /* Type declaration files to be included in compilation. */ 47 | "allowSyntheticDefaultImports": true 48 | /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 50 | 51 | /* Source Map Options */ 52 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 53 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 54 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 55 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 56 | 57 | /* Experimental Options */ 58 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 59 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 60 | } 61 | } --------------------------------------------------------------------------------