Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a copy of ESM-only files #7

Merged
merged 1 commit into from
Feb 26, 2024
Merged
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
5 changes: 5 additions & 0 deletions count-substring.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function countSubstring(string, substring) {
const pattern = new RegExp(substring, "g");
const match = string.match(pattern);
return match ? match.length : 0;
}
58 changes: 58 additions & 0 deletions find-tag-by-name.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import indexOfMatch from "./index-of-match.mjs";
import indexOfMatchEnd from "./index-of-match-end.mjs";
import countSubstring from "./count-substring.mjs";

export default function findTagByName(xml, tagName, options) {
const debug = (options && options.debug) || false;
const nested = !(options && typeof options.nested === false);

const startIndex = (options && options.startIndex) || 0;

if (debug) console.log("[xml-utils] starting findTagByName with", tagName, " and ", options);

const start = indexOfMatch(xml, `\<${tagName}[ \n\>\/]`, startIndex);
if (debug) console.log("[xml-utils] start:", start);
if (start === -1) return undefined;

const afterStart = xml.slice(start + tagName.length);

let relativeEnd = indexOfMatchEnd(afterStart, "^[^<]*[ /]>", 0);

const selfClosing = relativeEnd !== -1 && afterStart[relativeEnd - 1] === "/";
if (debug) console.log("[xml-utils] selfClosing:", selfClosing);

if (selfClosing === false) {
// check if tag has subtags with the same name
if (nested) {
let startIndex = 0;
let openings = 1;
let closings = 0;
while ((relativeEnd = indexOfMatchEnd(afterStart, "[ /]" + tagName + ">", startIndex)) !== -1) {
const clip = afterStart.substring(startIndex, relativeEnd + 1);
openings += countSubstring(clip, "<" + tagName + "[ \n\t>]");
closings += countSubstring(clip, "</" + tagName + ">");
// we can't have more openings than closings
if (closings >= openings) break;
startIndex = relativeEnd;
}
} else {
relativeEnd = indexOfMatchEnd(afterStart, "[ /]" + tagName + ">", 0);
}
}

const end = start + tagName.length + relativeEnd + 1;
if (debug) console.log("[xml-utils] end:", end);
if (end === -1) return undefined;

const outer = xml.slice(start, end);
// tag is like <gml:identifier codeSpace="OGP">urn:ogc:def:crs:EPSG::32617</gml:identifier>

let inner;
if (selfClosing) {
inner = null;
} else {
inner = outer.slice(outer.indexOf(">") + 1, outer.lastIndexOf("<"));
}

return { inner, outer, start, end };
}
8 changes: 8 additions & 0 deletions find-tag-by-path.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import findTagsByPath from "./find-tags-by-path.mjs";

export default function findTagByPath(xml, path, options) {
const debug = (options && options.debug) || false;
const found = findTagsByPath(xml, path, { debug, returnOnFirst: true });
if (Array.isArray(found) && found.length === 1) return found[0];
else return undefined;
}
19 changes: 19 additions & 0 deletions find-tags-by-name.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import findTagByName from "./find-tag-by-name.mjs";

export default function findTagsByName(xml, tagName, options) {
const tags = [];
const debug = (options && options.debug) || false;
const nested = options && typeof options.nested === "boolean" ? options.nested : true;
let startIndex = (options && options.startIndex) || 0;
let tag;
while ((tag = findTagByName(xml, tagName, { debug, startIndex }))) {
if (nested) {
startIndex = tag.start + 1 + tagName.length;
} else {
startIndex = tag.end;
}
tags.push(tag);
}
if (debug) console.log("findTagsByName found", tags.length, "tags");
return tags;
}
30 changes: 30 additions & 0 deletions find-tags-by-path.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import findTagsByName from "./find-tags-by-name.mjs";

export default function findTagsByPath(xml, path, options) {
const debug = (options && options.debug) || false;
const returnOnFirst = (options && options.returnOnFirst) || false;
let tags = findTagsByName(xml, path.shift(), { debug, nested: false });
if (debug) console.log("first tags are:", tags);
for (let pathIndex = 0; pathIndex < path.length; pathIndex++) {
const tagName = path[pathIndex];
if (debug) console.log("tagName:", tagName);
let allSubTags = [];
for (let tagIndex = 0; tagIndex < tags.length; tagIndex++) {
const tag = tags[tagIndex];
const subTags = findTagsByName(tag.outer, tagName, {
debug,
startIndex: 1
});
if (debug) console.log("subTags.length:", subTags.length);
if (subTags.length > 0) {
subTags.forEach(subTag => {
(subTag.start += tag.start), (subTag.end += tag.start);
});
if (returnOnFirst && pathIndex === path.length - 1) return [subTags[0]];
allSubTags = allSubTags.concat(subTags);
}
}
tags = allSubTags;
}
return tags;
}
21 changes: 21 additions & 0 deletions get-attribute.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default function getAttribute(tag, attributeName, options) {
const debug = (options && options.debug) || false;
if (debug) console.log("[xml-utils] getting " + attributeName + " in " + tag);

const xml = typeof tag === "object" ? tag.outer : tag;

// only search for attributes in the opening tag
const opening = xml.slice(0, xml.indexOf(">") + 1);

const quotechars = ['"', "'"];
for (let i = 0; i < quotechars.length; i++) {
const char = quotechars[i];
const pattern = attributeName + "\\=" + char + "([^" + char + "]*)" + char;
if (debug) console.log("[xml-utils] pattern:", pattern);

const re = new RegExp(pattern);
const match = re.exec(opening);
if (debug) console.log("[xml-utils] match:", match);
if (match) return match[1];
}
}
6 changes: 6 additions & 0 deletions index-of-match-end.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function indexOfMatchEnd(xml, pattern, startIndex) {
const re = new RegExp(pattern);
const match = re.exec(xml.slice(startIndex));
if (match) return startIndex + match.index + match[0].length - 1;
else return -1;
}
6 changes: 6 additions & 0 deletions index-of-match.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function indexOfMatch(xml, pattern, startIndex) {
const re = new RegExp(pattern);
const match = re.exec(xml.slice(startIndex));
if (match) return startIndex + match.index;
else return -1;
}
12 changes: 6 additions & 6 deletions index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { default as getAttribute } from "./get-attribute.js";
export { default as findTagByName } from "./find-tag-by-name.js";
export { default as findTagsByName } from "./find-tags-by-name.js";
export { default as findTagByPath } from "./find-tag-by-path.js";
export { default as findTagsByPath } from "./find-tags-by-path.js";
export { default as removeComments } from "./remove-comments.js";
export { default as getAttribute } from "./get-attribute.mjs";
export { default as findTagByName } from "./find-tag-by-name.mjs";
export { default as findTagsByName } from "./find-tags-by-name.mjs";
export { default as findTagByPath } from "./find-tag-by-path.mjs";
export { default as findTagsByPath } from "./find-tags-by-path.mjs";
export { default as removeComments } from "./remove-comments.mjs";
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,21 @@
"index-of-match.js",
"index-of-match-end.js",
"remove-comments.js",
"remove-tags-by-name.js"
"remove-tags-by-name.js",
"count-substring.mjs",
"find-tag-by-name.mjs",
"find-tag-by-path.mjs",
"find-tags-by-name.mjs",
"find-tags-by-path.mjs",
"get-attribute.mjs",
"index-of-match.mjs",
"index-of-match-end.mjs",
"remove-comments.mjs",
"remove-tags-by-name.mjs"
],
"scripts": {
"f": "npm run format",
"format": "npx prettier --arrow-parens=avoid --print-width=140 --trailing-comma=none --write *.js */*.js */*.mjs */*.ts",
"format": "npx prettier --arrow-parens=avoid --print-width=140 --trailing-comma=none --write *.js *.mjs */*.js */*.mjs */*.ts",
"setup": "cd test/data && bash setup.sh",
"test": "npm run test:js && npm run test:ts && npm run test:tsc && npm run test:esm",
"test:js": "node ./test/test.js",
Expand Down
3 changes: 3 additions & 0 deletions remove-comments.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function removeComments(xml) {
return xml.replace(/<!--[^]*-->/g, "");
}
11 changes: 11 additions & 0 deletions remove-tags-by-name.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import findTagByName from "./find-tag-by-name.mjs";

export default function removeTagsByName(xml, tagName, options) {
const debug = (options && options.debug) || false;
let tag;
while ((tag = findTagByName(xml, tagName, { debug }))) {
xml = xml.substring(0, tag.start) + xml.substring(tag.end);
if (debug) console.log("[xml-utils] removed:", tag);
}
return xml;
}
2 changes: 1 addition & 1 deletion test/test.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import test from "flug";
import { readFileSync } from "node:fs";
import { findTagByName, findTagsByName, findTagByPath, findTagsByPath, getAttribute } from "../index.mjs";
import { default as findTagsByNameDirect } from "../find-tags-by-name.js";
import { default as findTagsByNameDirect } from "../find-tags-by-name.mjs";

const iso = readFileSync("test/data/iso.xml", "utf-8");
const mrf = readFileSync("test/data/m_3008501_ne_16_1_20171018.mrf", "utf-8");
Expand Down