Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@
},
"homepage": "https://github.com/microsoft/connected-workbooks#readme",
"dependencies": {
"@xmldom/xmldom": "~0.8.4",
"jszip": "^3.5.0",
"xmldom-qsa": "^1.1.3"
"jszip": "^3.5.0"
},
"optionalDependencies": {
"@xmldom/xmldom": "~0.8.4"
},
"devDependencies": {
"@babel/core": "^7.14.6",
Expand Down
2 changes: 1 addition & 1 deletion src/utils/documentUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
Errors,
} from "./constants";
import { DataTypes } from "../types";
import { DOMParser } from "xmldom-qsa";
import { DOMParser } from "./domUtils";

const createOrUpdateProperty = (doc: Document, parent: Element, property: string, value?: string | null): void => {
if (value === undefined) {
Expand Down
78 changes: 78 additions & 0 deletions src/utils/domUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

/**
* Cross-platform DOM utilities that work in both Node.js and browser environments
*/

// TypeScript types for DOMParser and XMLSerializer constructors
type DOMParserConstructor = new () => DOMParser;
type XMLSerializerConstructor = new () => XMLSerializer;

let domParserCache: DOMParserConstructor | undefined;
let xmlSerializerCache: XMLSerializerConstructor | undefined;

/**
* Gets a DOMParser implementation that works in both browser and Node.js environments
* In browsers, uses the native DOMParser
* In Node.js, requires the optional @xmldom/xmldom dependency
*/
export function getDOMParser(): DOMParserConstructor {
if (domParserCache) {
return domParserCache;
}

// Browser environment - use native implementation
if (typeof window !== 'undefined' && window.DOMParser) {
domParserCache = window.DOMParser;
return window.DOMParser;
}

// Node.js environment - try to load @xmldom/xmldom
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const xmldom = require('@xmldom/xmldom');
domParserCache = xmldom.DOMParser;
return xmldom.DOMParser;
} catch (error) {
throw new Error(
'DOM implementation not available in Node.js environment. ' +
'Please install the optional dependency: npm install @xmldom/xmldom'
);
}
}

/**
* Gets an XMLSerializer implementation that works in both browser and Node.js environments
* In browsers, uses the native XMLSerializer
* In Node.js, requires the optional @xmldom/xmldom dependency
*/
export function getXMLSerializer(): XMLSerializerConstructor {
if (xmlSerializerCache) {
return xmlSerializerCache;
}

// Browser environment - use native implementation
if (typeof window !== 'undefined' && window.XMLSerializer) {
xmlSerializerCache = window.XMLSerializer;
return window.XMLSerializer;
}

// Node.js environment - try to load @xmldom/xmldom
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const xmldom = require('@xmldom/xmldom');
xmlSerializerCache = xmldom.XMLSerializer;
return xmldom.XMLSerializer;
} catch (error) {
throw new Error(
'DOM implementation not available in Node.js environment. ' +
'Please install the optional dependency: npm install @xmldom/xmldom'
);
}
}

// For backward compatibility, export the classes directly
// These will throw helpful error messages if @xmldom/xmldom is not available in Node.js
export const DOMParser: DOMParserConstructor = getDOMParser();
export const XMLSerializer: XMLSerializerConstructor = getXMLSerializer();
2 changes: 1 addition & 1 deletion src/utils/mashupDocumentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from "./constants";
import { arrayUtils } from ".";
import { Metadata } from "../types";
import { DOMParser, XMLSerializer } from "xmldom-qsa";
import { DOMParser, XMLSerializer } from "./domUtils";

export const replaceSingleQuery = async (base64Str: string, queryName: string, queryMashupDoc: string): Promise<string> => {
const { version, packageOPC, permissionsSize, permissions, metadata, endBuffer } = getPackageComponents(base64Str);
Expand Down
2 changes: 1 addition & 1 deletion src/utils/pqUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import JSZip from "jszip";
import { maxQueryLength, URLS, BOM, Errors } from "./constants";
import { generateMashupXMLTemplate, generateCustomXmlFilePath } from "../generators";
import { DOMParser } from "xmldom-qsa";
import { DOMParser } from "./domUtils";
import arrayUtils from "./arrayUtils";

type CustomXmlFile = {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/tableUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from "./constants";
import documentUtils from "./documentUtils";
import { generateUUID } from "./uuid";
import { DOMParser, XMLSerializer } from "xmldom-qsa";
import { DOMParser, XMLSerializer } from "./domUtils";

/**
* Update initial data for a table, its sheet, query table, and defined name if provided.
Expand Down
2 changes: 1 addition & 1 deletion src/utils/xmlInnerPartsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
Errors,
} from "./constants";
import documentUtils from "./documentUtils";
import { DOMParser, XMLSerializer } from "xmldom-qsa";
import { DOMParser, XMLSerializer } from "./domUtils";

/**
* Helper function to check for XML parser errors without using querySelector
Expand Down
2 changes: 1 addition & 1 deletion tests/documentUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DataTypes } from "../src/types";
import { documentUtils } from "../src/utils";
import { element } from "../src/utils/constants";
import { describe, test, expect } from '@jest/globals';
import { DOMParser } from 'xmldom-qsa';
import { DOMParser } from '../src/utils/domUtils';

describe("Document Utils tests", () => {
test("ResolveType date not supported success", () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/xmlInnerPartsUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { describe, test, expect } from '@jest/globals';
import JSZip from "jszip";
import { SIMPLE_BLANK_TABLE_TEMPLATE, SIMPLE_QUERY_WORKBOOK_TEMPLATE, WORKBOOK_TEMPLATE_MOVED_TABLE } from "../src/workbookTemplate";
import { customXML, Errors } from "../src/utils/constants";
import { DOMParser } from "xmldom-qsa";
import { DOMParser } from "../src/utils/domUtils";

describe("Workbook Manager tests", () => {
const mockConnectionString = `<connections xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xr16="http://schemas.microsoft.com/office/spreadsheetml/2017/revision16" mc:Ignorable="xr16">
Expand Down