🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@allurereport/reader-api

Package Overview
Dependencies
Maintainers
2
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@allurereport/reader-api - npm Package Compare versions

Comparing version
3.0.0-beta.5
to
3.0.0-beta.6
+2
dist/detect.d.ts
declare const detectContentType: (buffer: Uint8Array) => string | undefined;
export { detectContentType };
const rawMagics = [
{
name: "video/mp4",
priority: 60,
clause: {
clause: "match",
value: "ftypmp42",
type: "string",
offset: "4",
},
extensions: [".mp4", ".mp4v", ".mpg4"],
},
{
name: "video/mp4",
priority: 60,
clause: {
clause: "match",
value: "ftypmp41",
type: "string",
offset: "4",
},
extensions: [".mp4", ".mp4v", ".mpg4"],
},
{
name: "image/svg+xml",
priority: 50,
clause: {
clause: "and",
nested: [
{
clause: "match",
value: "<svg",
type: "string",
offset: "0",
},
{
clause: "match",
value: "http://www.w3.org/2000/svg",
type: "string",
offset: "5:256",
},
],
},
extensions: [".svg", ".svgz"],
},
{
name: "image/png",
priority: 50,
clause: {
clause: "match",
value: "\\x89PNG\\x0d\\x0a\\x1a\\x0a",
type: "string",
offset: "0",
},
extensions: [".png"],
},
{
name: "application/x-gtar",
priority: 50,
clause: {
clause: "match",
value: "ustar \\0",
type: "string",
offset: "257",
},
extensions: [".gtar"],
},
{
name: "application/pdf",
priority: 50,
clause: {
clause: "match",
value: "\\xef\\xbb\\xbf%PDF-",
type: "string",
offset: "0",
},
extensions: [".pdf"],
},
{
name: "image/gif",
priority: 50,
clause: {
clause: "match",
value: "GIF89a",
type: "string",
offset: "0",
},
extensions: [".gif"],
},
{
name: "image/gif",
priority: 50,
clause: {
clause: "match",
value: "GIF87a",
type: "string",
offset: "0",
},
extensions: [".gif"],
},
{
name: "image/bmp",
priority: 50,
clause: {
clause: "and",
nested: [
{
clause: "match",
value: "BM",
type: "string",
offset: "0",
},
{
clause: "and",
nested: [
{
clause: "match",
value: "0x0100",
type: "string",
offset: "26",
},
{
clause: "or",
nested: [
{
clause: "match",
value: "0x0000",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x0100",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x0400",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x0800",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x1000",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x1800",
type: "string",
offset: "28",
},
{
clause: "match",
value: "0x2000",
type: "string",
offset: "28",
},
],
},
],
},
],
},
extensions: [".bmp", ".dib"],
},
{
name: "application/pdf",
priority: 50,
clause: {
clause: "match",
value: "%PDF-",
type: "string",
offset: "0",
},
extensions: [".pdf"],
},
{
name: "image/tiff",
priority: 50,
clause: {
clause: "match",
value: "MM\\x00\\x2b",
type: "string",
offset: "0",
},
extensions: [".tiff", ".tif"],
},
{
name: "image/tiff",
priority: 50,
clause: {
clause: "match",
value: "MM\\x00\\x2a",
type: "string",
offset: "0",
},
extensions: [".tiff", ".tif"],
},
{
name: "image/tiff",
priority: 50,
clause: {
clause: "match",
value: "II\\x2a\\x00",
type: "string",
offset: "0",
},
extensions: [".tiff", ".tif"],
},
{
name: "application/zip",
priority: 50,
clause: {
clause: "match",
value: "PK\\x07\\x08",
type: "string",
offset: "0",
},
extensions: [".zip"],
},
{
name: "application/zip",
priority: 50,
clause: {
clause: "match",
value: "PK\\005\\006",
type: "string",
offset: "0",
},
extensions: [".zip"],
},
{
name: "application/zip",
priority: 50,
clause: {
clause: "match",
value: "PK\\003\\004",
type: "string",
offset: "0",
},
extensions: [".zip"],
},
{
name: "image/jpeg",
priority: 50,
clause: {
clause: "match",
value: "0xffd8ff",
type: "string",
offset: "0",
},
extensions: [".jpg", ".jpeg", ".jpe", ".jif", ".jfif", ".jfi"],
},
{
name: "application/gzip",
priority: 45,
clause: {
clause: "match",
value: "\\x1f\\x8b",
type: "string",
offset: "0",
},
extensions: [".gz", ".tgz", "-gz"],
},
{
name: "application/gzip",
priority: 45,
clause: {
clause: "match",
value: "\\037\\213",
type: "string",
offset: "0",
},
extensions: [".gz", ".tgz", "-gz"],
},
{
name: "application/pdf",
priority: 40,
clause: {
clause: "and",
nested: [
{
clause: "match",
value: "%%",
type: "string",
offset: "0:128",
},
{
clause: "match",
value: "%PDF-2.",
type: "string",
offset: "1:512",
},
],
},
extensions: [".pdf"],
},
{
name: "application/pdf",
priority: 40,
clause: {
clause: "and",
nested: [
{
clause: "match",
value: "%%",
type: "string",
offset: "0:128",
},
{
clause: "match",
value: "%PDF-1.",
type: "string",
offset: "1:512",
},
],
},
extensions: [".pdf"],
},
{
name: "application/x-tar",
priority: 40,
clause: {
clause: "match",
value: "ustar\\0",
type: "string",
offset: "257",
},
extensions: [".tar"],
},
{
name: "application/pdf",
priority: 20,
clause: {
clause: "match",
value: "%PDF-2.",
type: "string",
offset: "1:512",
},
extensions: [".pdf"],
},
{
name: "application/pdf",
priority: 20,
clause: {
clause: "match",
value: "%PDF-1.",
type: "string",
offset: "1:512",
},
extensions: [".pdf"],
},
];
const decodeString = (value, type) => {
if (value.startsWith("0x")) {
const vals = new Uint8Array((value.length - 2) / 2);
for (let i = 0; i < vals.length; i++) {
vals[i] = parseInt(value.substring(2 + i * 2, 4 + i * 2), 16);
}
return vals;
}
const decoded = [];
for (let i = 0; i < value.length; i++) {
if (value[i] === "\\") {
if (value[i + 1] === "\\") {
decoded.push(92);
i++;
}
else if (value[i + 1] === "x") {
decoded.push(parseInt(value.substring(i + 2, i + 4), 16));
i += 3;
}
else if (value[i + 1] === "r") {
decoded.push(13);
i++;
}
else if (value[i + 1] === "n") {
decoded.push(10);
i++;
}
else {
let j = i + 1;
while (j < i + 4 && j < value.length && /\d/.test(value[j])) {
j++;
}
decoded.push(parseInt(`0${value.substring(i + 1, j)}`, 10));
i = j - 1;
}
}
else {
decoded.push(value.charCodeAt(i));
}
}
const chars = decoded;
let bytes;
if (type === "unicodeLE") {
bytes = new Uint8Array(chars.length * 2);
for (let i = 0; i < chars.length; i++) {
bytes[i * 2] = chars[i] & 0xff;
bytes[i * 2 + 1] = chars[i] >> 8;
}
}
else if (type === "unicodeBE") {
bytes = new Uint8Array(chars.length * 2);
for (let i = 0; i < chars.length; i++) {
bytes[i * 2] = chars[i] >> 8;
bytes[i * 2 + 1] = chars[i] & 0xff;
}
}
else {
bytes = new Uint8Array(chars.length);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = chars[i];
}
}
return bytes;
};
class AndClause {
constructor(clauses) {
this.clauses = clauses;
}
eval(data) {
for (const clause of this.clauses) {
if (!clause.eval(data)) {
return false;
}
}
return true;
}
}
class OrClause {
constructor(clauses) {
this.clauses = clauses;
}
eval(data) {
for (const clause of this.clauses) {
if (!clause.eval(data)) {
return true;
}
}
return false;
}
}
class MagicMatchClause {
constructor(pattern, mask, start = 0, end = start) {
this.pattern = pattern;
this.mask = mask;
this.start = start;
this.end = end;
this.eval = (data) => {
if (data.length < this.pattern.length + this.start) {
return false;
}
for (let i = this.start; i <= this.end; i++) {
let match = true;
for (let j = 0; match && j < this.pattern.length; j++) {
const masked = data[i + j] & this.mask[j];
match = masked === this.pattern[j];
}
if (match) {
return true;
}
}
return false;
};
}
}
const parseClause = (rawClause) => {
if (rawClause.clause === "and") {
return new AndClause(rawClause.nested.map((nested) => parseClause(nested)));
}
if (rawClause.clause === "or") {
return new OrClause(rawClause.nested.map((nested) => parseClause(nested)));
}
return createMagicMatch(rawClause.value, rawClause.mask, rawClause.offset, rawClause.type);
};
const parseMagics = (data) => {
return data.map((m) => {
return {
priority: m.priority,
type: m.name,
extensions: m.extensions,
clause: parseClause(m.clause),
};
});
};
const createMagicMatch = (value, mask, offset, type = "string") => {
const decodedValue = decodeString(value, type);
const decodedMask = mask ? decodeString(value, type) : undefined;
const patternLength = Math.max(decodedValue.length, decodedMask?.length ?? 0);
const resPattern = new Uint8Array(patternLength);
const resMask = new Uint8Array(patternLength);
for (let i = 0; i < patternLength; i++) {
if (decodedMask && i < decodedMask.length) {
resMask[i] = decodedMask[i];
}
else {
resMask[i] = -1;
}
if (i < decodedValue.length) {
resPattern[i] = decodedValue[i] & resMask[i];
}
else {
resPattern[i] = 0;
}
}
let start = 0;
let end = 0;
if (offset) {
if (offset.indexOf(":") > 0) {
const [startRaw, endRaw] = offset.split(":");
start = +startRaw;
end = +endRaw;
}
else {
start = +offset;
end = start;
}
}
return new MagicMatchClause(resPattern, resMask, start, end);
};
const magics = parseMagics(rawMagics);
const detectContentType = (buffer) => {
if (buffer.length === 0) {
return undefined;
}
let result = [];
let currentPriority = -1;
for (const magic of magics) {
if (currentPriority > 0 && currentPriority > magic.priority) {
break;
}
if (magic.clause.eval(buffer)) {
if (currentPriority === magic.priority) {
result.push(magic.type);
}
else {
result = [magic.type];
currentPriority = magic.priority;
}
}
}
if (result.length > 0) {
return result[0];
}
return undefined;
};
export { detectContentType };
export declare const extension: (fileName: string, contentType?: string) => string | undefined;
export declare const lookupContentType: (fileName: string) => string | undefined;
import { extension as extensionFromContentType, lookup } from "mime-types";
import { extname } from "node:path";
export const extension = (fileName, contentType) => {
const ext = extname(fileName);
if (ext !== "") {
return ext;
}
if (contentType) {
const result = extensionFromContentType(contentType);
if (result === false) {
return undefined;
}
return `.${result}`;
}
return undefined;
};
export const lookupContentType = (fileName) => {
const res = lookup(fileName);
if (res === false) {
return undefined;
}
return res;
};
+2
-0
export type * from "./model.js";
export type * from "./reader.js";
export * from "./resultFile.js";
export { detectContentType } from "./detect.js";
export { extension, lookupContentType } from "./utils.js";
export * from "./resultFile.js";
export { detectContentType } from "./detect.js";
export { extension, lookupContentType } from "./utils.js";
+10
-3

@@ -6,8 +6,13 @@ import type { ResultFile } from "@allurereport/plugin-api";

export declare abstract class BaseResultFile implements ResultFile {
#private;
fileName: string;
extension: string | false;
contentType: string | undefined | false;
protected constructor(fileName: string);
protected abstract getContent(): ReadStream | undefined;
protected abstract readMagicHeader(): Uint8Array | undefined;
abstract getContentLength(): number | undefined;
getContentType(): string | undefined;
getOriginalFileName(): string;
getExtension(): string;
asJson<T>(): Promise<T | undefined>;

@@ -20,5 +25,6 @@ asUtf8String(): Promise<string | undefined>;

export declare class BufferResultFile extends BaseResultFile {
buffer: Buffer;
constructor(buffer: Buffer, fileName: string);
protected getContent(): ReadStream | undefined;
buffer: Uint8Array;
constructor(buffer: Uint8Array, fileName: string);
protected getContent(): ReadStream;
protected readMagicHeader(): Uint8Array;
getContentLength(): number | undefined;

@@ -30,2 +36,3 @@ }

protected getContent(): ReadStream | undefined;
protected readMagicHeader(): Uint8Array | undefined;
getContentLength(): number | undefined;

@@ -32,0 +39,0 @@ }

@@ -0,16 +1,26 @@

var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _BaseResultFile_instances, _BaseResultFile_detectContentType;
import { lookup } from "mime-types";
import { ReadStream, createReadStream, createWriteStream, existsSync, statSync } from "node:fs";
import { ReadStream, closeSync, createReadStream, createWriteStream, existsSync, openSync, readSync, statSync, } from "node:fs";
import "node:fs/promises";
import { basename } from "node:path";
import { pipeline } from "node:stream/promises";
import { detectContentType } from "./detect.js";
import { extension } from "./utils.js";
export class BaseResultFile {
constructor(fileName) {
_BaseResultFile_instances.add(this);
this.extension = false;
this.contentType = false;
this.fileName = fileName;
}
getContentType() {
const res = lookup(this.getOriginalFileName());
if (res === false) {
return undefined;
if (this.contentType === false) {
this.contentType = __classPrivateFieldGet(this, _BaseResultFile_instances, "m", _BaseResultFile_detectContentType).call(this);
}
return res;
return this.contentType;
}

@@ -20,2 +30,8 @@ getOriginalFileName() {

}
getExtension() {
if (this.extension === false) {
this.extension = extension(this.getOriginalFileName()) ?? extension("", this.getContentType()) ?? "";
}
return this.extension;
}
async asJson() {

@@ -40,2 +56,14 @@ return await this.readContent(readSteamToJson);

}
_BaseResultFile_instances = new WeakSet(), _BaseResultFile_detectContentType = function _BaseResultFile_detectContentType() {
const res = lookup(this.getOriginalFileName());
if (res === false) {
const magicHeader = this.readMagicHeader();
if (!magicHeader) {
return undefined;
}
return detectContentType(magicHeader);
}
return res;
};
const magicHeaderLength = 1024;
export class BufferResultFile extends BaseResultFile {

@@ -49,2 +77,5 @@ constructor(buffer, fileName) {

}
readMagicHeader() {
return this.buffer.subarray(0, magicHeaderLength);
}
getContentLength() {

@@ -67,2 +98,24 @@ return this.buffer.length;

}
readMagicHeader() {
if (existsSync(this.path)) {
const buf = new Uint8Array(magicHeaderLength);
const fd = openSync(this.path, "r");
try {
const size = readSync(fd, buf, 0, magicHeaderLength, null);
if (size === 0) {
return undefined;
}
if (size < magicHeaderLength) {
return buf.subarray(0, size);
}
return buf;
}
finally {
closeSync(fd);
}
}
else {
return undefined;
}
}
getContentLength() {

@@ -69,0 +122,0 @@ return statSync(this.path, { throwIfNoEntry: false })?.size;

{
"name": "@allurereport/reader-api",
"version": "3.0.0-beta.5",
"version": "3.0.0-beta.6",
"description": "Allure Reader API",

@@ -30,4 +30,4 @@ "keywords": [

"dependencies": {
"@allurereport/core-api": "3.0.0-beta.5",
"@allurereport/plugin-api": "3.0.0-beta.5",
"@allurereport/core-api": "3.0.0-beta.6",
"@allurereport/plugin-api": "3.0.0-beta.6",
"mime-types": "^2.1.35"

@@ -34,0 +34,0 @@ },