diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..1b5bfa1 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,75 @@ +language: en-US +tone_instructions: '' +early_access: false +enable_free_tier: true +reviews: + profile: chill + request_changes_workflow: false + high_level_summary: true + high_level_summary_placeholder: '@coderabbitai summary' + auto_title_placeholder: '@coderabbitai' + review_status: true + poem: false + collapse_walkthrough: false + sequence_diagrams: true + path_filters: [] + path_instructions: [] + abort_on_close: true + auto_review: + enabled: true + auto_incremental_review: true + ignore_title_keywords: [] + labels: [] + drafts: false + base_branches: [] + tools: + shellcheck: + enabled: true + ruff: + enabled: true + markdownlint: + enabled: true + github-checks: + enabled: true + timeout_ms: 90000 + languagetool: + enabled: true + enabled_only: false + level: default + biome: + enabled: true + hadolint: + enabled: true + swiftlint: + enabled: true + phpstan: + enabled: true + level: default + golangci-lint: + enabled: true + yamllint: + enabled: true + gitleaks: + enabled: true + checkov: + enabled: true + detekt: + enabled: true + eslint: + enabled: true + rubocop: + enabled: true + buf: + enabled: true +chat: + auto_reply: true +knowledge_base: + opt_out: false + learnings: + scope: auto + issues: + scope: auto + jira: + project_keys: [] + linear: + team_keys: [] diff --git a/demo/esp32/src/main.cpp b/demo/esp32/src/main.cpp index 8c298a4..c098bab 100644 --- a/demo/esp32/src/main.cpp +++ b/demo/esp32/src/main.cpp @@ -6,7 +6,7 @@ #include #include "svelteesp32async.h" -#if SVELTEESP32_COUNT != 10 +#if SVELTEESP32_COUNT != 11 #error Invalid file count #endif @@ -40,7 +40,7 @@ void loop() {} #include #include "svelteesp32psychic.h" -#if SVELTEESP32_COUNT != 10 +#if SVELTEESP32_COUNT != 11 #error Invalid file count #endif diff --git a/demo/svelte/dist/favicon.png.gz b/demo/svelte/dist/favicon.png.gz new file mode 100644 index 0000000..8e969cf Binary files /dev/null and b/demo/svelte/dist/favicon.png.gz differ diff --git a/demo/svelte/dist/gallery/image-1a.jpg b/demo/svelte/dist/gallery/image-1a.jpg new file mode 100644 index 0000000..bd4ff1f Binary files /dev/null and b/demo/svelte/dist/gallery/image-1a.jpg differ diff --git a/demo/svelte/package-lock.json b/demo/svelte/package-lock.json index 48a2ef0..88f899b 100644 --- a/demo/svelte/package-lock.json +++ b/demo/svelte/package-lock.json @@ -11,8 +11,8 @@ "@rollup/plugin-swc": "^0.3.1", "@sveltejs/vite-plugin-svelte": "^3.1.1", "@tsconfig/svelte": "^5.0.4", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", + "@typescript-eslint/eslint-plugin": "^8.2.0", + "@typescript-eslint/parser": "^8.2.0", "autoprefixer": "^10.4.20", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", @@ -1494,17 +1494,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz", - "integrity": "sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/type-utils": "8.1.0", - "@typescript-eslint/utils": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1528,16 +1528,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.1.0.tgz", - "integrity": "sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { @@ -1557,14 +1557,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz", - "integrity": "sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1575,14 +1575,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz", - "integrity": "sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/utils": "8.1.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1600,9 +1600,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.1.0.tgz", - "integrity": "sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "license": "MIT", "engines": { @@ -1614,14 +1614,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz", - "integrity": "sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1643,16 +1643,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz", - "integrity": "sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1666,13 +1666,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz", - "integrity": "sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { diff --git a/demo/svelte/package.json b/demo/svelte/package.json index 6a1b085..426be92 100644 --- a/demo/svelte/package.json +++ b/demo/svelte/package.json @@ -9,7 +9,7 @@ }, "scripts": { "dev": "vite dev --host", - "build": "vite build", + "build": "vite build && gzip -c ./dist/favicon.png > ./dist/favicon.png.gz && cp ./dist/gallery/image-1.jpg ./dist/gallery/image-1a.jpg", "preview": "vite preview", "test": "npm run test:integration && npm run test:unit", "ts:check": "svelte-check --tsconfig ./tsconfig.json", @@ -23,8 +23,8 @@ "@rollup/plugin-swc": "^0.3.1", "@sveltejs/vite-plugin-svelte": "^3.1.1", "@tsconfig/svelte": "^5.0.4", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", + "@typescript-eslint/eslint-plugin": "^8.2.0", + "@typescript-eslint/parser": "^8.2.0", "autoprefixer": "^10.4.20", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", diff --git a/src/consoleColor.ts b/src/consoleColor.ts index d8dd72e..311f2b2 100644 --- a/src/consoleColor.ts +++ b/src/consoleColor.ts @@ -1,5 +1,5 @@ -export const greenLog = (s: string): string => `\u001B[32m ${s} \u001B[0m`; +export const greenLog = (s: string): string => `\u001B[32m${s}\u001B[0m`; -export const yellowLog = (s: string): string => `\u001B[33m ${s} \u001B[0m`; +export const yellowLog = (s: string): string => `\u001B[33m${s}\u001B[0m`; -export const redLog = (s: string): string => `\u001B[31m ${s} \u001B[0m`; +export const redLog = (s: string): string => `\u001B[31m${s}\u001B[0m`; diff --git a/src/file.ts b/src/file.ts index fb76143..6a73b6f 100644 --- a/src/file.ts +++ b/src/file.ts @@ -1,22 +1,43 @@ +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; import path from 'node:path'; import { globSync } from 'glob'; import { cmdLine } from './commandLine'; -import { redLog } from './consoleColor'; +import { redLog, yellowLog } from './consoleColor'; -export const getFiles = (): string[] => { - let files = globSync('**/*', { cwd: cmdLine.sourcepath, nodir: true }); - files = files.filter((filename) => { +const findSimilarFiles = (files: Map): string[][] => { + const contentComparer: Map = new Map(); + for (const [filename, content] of files.entries()) { + const hash = createHash('sha256').update(content).digest('hex'); + if (contentComparer.has(hash)) contentComparer.get(hash)!.push(filename); + else contentComparer.set(hash, [filename]); + } + + const result: string[][] = []; + for (const filenames of contentComparer.values()) if (filenames.length > 1) result.push(filenames); + return result; +}; + +export const getFiles = (): Map => { + let filenames = globSync('**/*', { cwd: cmdLine.sourcepath, nodir: true }); + filenames = filenames.filter((filename) => { const extension = path.extname(filename); if (['.gz', '.brottli', '.br'].includes(extension)) { const original = filename.slice(0, -1 * extension.length); - if (files.includes(original)) { - console.log(redLog(`${filename} skipped because is perhaps a compressed version of ${original}`)); + if (filenames.includes(original)) { + console.log(redLog(` ${filename} skipped because is perhaps a compressed version of ${original}`)); return false; } } return true; }); - return files.sort(); + + const result: Map = new Map(); + for (const filename of filenames) + result.set(filename, readFileSync(path.join(cmdLine.sourcepath, filename), { flag: 'r' })); + for (const sameFile of findSimilarFiles(result)) + console.log(yellowLog(` ${sameFile.join(', ')} files look like identical`)); + return result; }; diff --git a/src/index.ts b/src/index.ts index 3a783ad..8992c70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ /* eslint-disable unicorn/prefer-string-replace-all */ import { createHash } from 'node:crypto'; -import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { gzipSync } from 'node:zlib'; @@ -19,18 +19,22 @@ const summary = { const sources: CppCodeSources = []; const filesByExtension: ExtensionGroups = []; + +console.log('Collecting source files'); const files = getFiles(); -if (files.length === 0) { +if (files.size === 0) { console.error(`Directory ${cmdLine.sourcepath} is empty`); process.exit(1); } -const rightPad = files.reduce((p, c) => (c.length > p ? c.length : p), 0); -for (const file of files) { - const mime = lookup(file) || 'text/plain'; +console.log(); +console.log('Translation to header file'); +const longestFilename = [...files.keys()].reduce((p, c) => (c.length > p ? c.length : p), 0); +for (const [originalFilename, content] of files) { + const mime = lookup(originalFilename) || 'text/plain'; summary.filecount++; - const filename = file.replace(/\\/g, '/'); + const filename = originalFilename.replace(/\\/g, '/'); const dataname = filename.replace(/[./-]/g, '_'); let extension = path.extname(filename).toUpperCase(); if (extension.startsWith('.')) extension = extension.slice(1); @@ -39,7 +43,6 @@ for (const file of files) { if (group) group.count += 1; else filesByExtension.push({ extension, count: 1 }); - const content = readFileSync(path.join(cmdLine.sourcepath, file), { flag: 'r' }); const md5 = createHash('md5').update(content).digest('hex'); summary.size += content.length; const zipContent = gzipSync(content, { level: 9 }); @@ -58,7 +61,7 @@ for (const file of files) { }); console.log( greenLog( - `[${file}] ${' '.repeat(rightPad - file.length)} ✓ gzip used (${content.length} -> ${zipContent.length} = ${zipRatio}%)` + ` [${originalFilename}] ${' '.repeat(longestFilename - originalFilename.length)} ✓ gzip used (${content.length} -> ${zipContent.length} = ${zipRatio}%)` ) ); } else { @@ -74,7 +77,7 @@ for (const file of files) { }); console.log( yellowLog( - `[${file}] ${' '.repeat(rightPad - file.length)} x gzip unused ${content.length <= 1024 ? `(too small) ` : ''}(${content.length} -> ${zipContent.length} = ${zipRatio}%)` + ` [${originalFilename}] ${' '.repeat(longestFilename - originalFilename.length)} x gzip unused ${content.length <= 1024 ? `(too small) ` : ''}(${content.length} -> ${zipContent.length} = ${zipRatio}%)` ) ); }