{"id":23137750,"url":"https://github.com/ch8n/1filekt","last_synced_at":"2025-04-04T09:43:09.708Z","repository":{"id":267655611,"uuid":"901946726","full_name":"ch8n/1FileKt","owner":"ch8n","description":"One file merges all the directories of a folder into one markdown file, makes it easier for LLM ingestion of codebase","archived":false,"fork":false,"pushed_at":"2024-12-13T19:49:26.000Z","size":104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-09T20:22:39.566Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ch8n.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-11T15:59:51.000Z","updated_at":"2024-12-13T19:49:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"ca1b4dda-7a55-4438-83cc-578741957e64","html_url":"https://github.com/ch8n/1FileKt","commit_stats":null,"previous_names":["ch8n/1filekt"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch8n%2F1FileKt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch8n%2F1FileKt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch8n%2F1FileKt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch8n%2F1FileKt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ch8n","download_url":"https://codeload.github.com/ch8n/1FileKt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247157087,"owners_count":20893203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-17T13:08:51.645Z","updated_at":"2025-04-04T09:43:09.694Z","avatar_url":"https://github.com/ch8n.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 1FileKt\nFeed your entire codebase to GPTs/LLM. 1 file for your entire codebase ingestion.\n\n# How to use\n\n```kotlin\nval directoryPath = \"/Users/chetan.gupta/Desktop/ch8n/rough/1fileKt\"\n    val rootDirectory = File(directoryPath)\n    val ignorePatterns = mutableListOf\u003cString\u003e(\n        \"merged_content.md\",\n        \"**/build/\", // Exclude all build directories\n        \"build/\",     // Exclude build directories at root\n        \"gradlew\", \"gradlew.bat\",\n        \".gradle/\",   // Exclude .gradle directory and its contents\n        \"gradle/\",    // Exclude gradle directory and its contents\n        \"**/resources\",\n        \".idea/\",     // Exclude .idea directory and its contents\n        \".kotlin/\",   // Exclude .kotlin directory and its contents\n        \".gitignore\", \".git/\", \".git\", // Exclude git related files/directories\n        \"*.iws\", \"*.iml\", \"*.ipr\",\n        \"out/\",             // Exclude out directories and contents\n        \"**/src/main/**/out/\", \"**/src/test/**/out/\",\n        \"*.classpath\", \"*.factorypath\",\n        \".apt_generated\", \".project\", \".settings\", \".springBeans\", \".sts4-cache\",\n        \"bin/\",             // Exclude bin directories and contents\n        \"**/src/main/**/bin/\", \"**/src/test/**/bin/\",\n        \"nbproject/private/\", \"nbbuild/\", \"dist/\", \"nbdist/\", \".nb-gradle/\",\n        \".vscode/\",\n        \".DS_Store\"\n    )\n    val oneFile = OneFile()\n    val outputFile = oneFile.execute(rootDirectory, ignorePatterns)\n    print(outputFile.readText())\n```\n\n# output \n```plaintext\n============\nDirectory:\n============\n├── .gradle\n├── .idea\n├── .kotlin\n├── build\n├── gradle\n├── src\n│   ├── main\n│   │   ├── kotlin\n│   │   │   └── Main.kt\n│   └── test\n│       ├── kotlin\n├── build.gradle.kts\n├── gradle.properties\n└── settings.gradle.kts\n\n============\nbuild.gradle.kts : /Users/chetan.gupta/Desktop/ch8n/rough/1fileKt/build.gradle.kts\n============\nplugins {\n    kotlin(\"jvm\") version \"2.0.10\"\n}\n\ngroup = \"dev.ch8n\"\nversion = \"1.0-SNAPSHOT\"\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    testImplementation(kotlin(\"test\"))\n}\n\ntasks.test {\n    useJUnitPlatform()\n}\n\n============\nsettings.gradle.kts : /Users/chetan.gupta/Desktop/ch8n/rough/1fileKt/settings.gradle.kts\n============\nrootProject.name = \"1fileKt\"\n\n\n\n============\ngradle.properties : /Users/chetan.gupta/Desktop/ch8n/rough/1fileKt/gradle.properties\n============\nkotlin.code.style=official\n\n\n============\nMain.kt : /Users/chetan.gupta/Desktop/ch8n/rough/1fileKt/src/main/kotlin/Main.kt\n============\nimport java.io.File\nimport java.nio.file.FileSystems\nimport java.nio.file.PathMatcher\n\nfun main() {\n    val directoryPath = \"/Users/chetan.gupta/Desktop/ch8n/rough/1fileKt\"\n    val rootDirectory = File(directoryPath)\n\n    if (!rootDirectory.isDirectory) {\n        println(\"The provided path is not a directory.\")\n        return\n    }\n\n    val excludePatternsInput = mutableListOf\u003cString\u003e(\n        \"merged_content.md\",\n        \"**/build/\", // Exclude all build directories\n        \"build/\",     // Exclude build directories at root\n        \"gradlew\", \"gradlew.bat\",\n        \".gradle/\",   // Exclude .gradle directory and its contents\n        \"gradle/\",    // Exclude gradle directory and its contents\n        \"**/resources\",\n        \".idea/\",     // Exclude .idea directory and its contents\n        \".kotlin/\",   // Exclude .kotlin directory and its contents\n        \".gitignore\", \".git/\", \".git\" , // Exclude git related files/directories\n        \"*.iws\", \"*.iml\", \"*.ipr\",\n        \"out/\",             // Exclude out directories and contents\n        \"**/src/main/**/out/\", \"**/src/test/**/out/\",\n        \"*.classpath\", \"*.factorypath\",\n        \".apt_generated\", \".project\", \".settings\", \".springBeans\", \".sts4-cache\",\n        \"bin/\",             // Exclude bin directories and contents\n        \"**/src/main/**/bin/\", \"**/src/test/**/bin/\",\n        \"nbproject/private/\", \"nbbuild/\", \"dist/\", \"nbdist/\", \".nb-gradle/\",\n        \".vscode/\",\n        \".DS_Store\"\n    )\n\n    // Separate exclude and include patterns\n    val excludePatterns = excludePatternsInput.filter { !it.startsWith(\"!\") }\n        .map { adjustPattern(it) }\n    val includePatterns = excludePatternsInput.filter { it.startsWith(\"!\") }\n        .map { adjustPattern(it.removePrefix(\"!\")) }\n\n    val excludeMatchers = excludePatterns.map { pattern -\u003e\n        FileSystems.getDefault().getPathMatcher(\"glob:$pattern\")\n    }\n\n    val includeMatchers = includePatterns.map { pattern -\u003e\n        FileSystems.getDefault().getPathMatcher(\"glob:$pattern\")\n    }\n\n    var fileCount = 0\n    var directoryCount = 0\n    var totalLines = 0\n    var totalWords = 0\n\n    val outputFile = File(rootDirectory, \"merged_content.md\")\n    outputFile.bufferedWriter().use { writer -\u003e\n        // Write directory structure\n        writer.write(\"============\\n\")\n        writer.write(\"Directory:\\n\")\n        writer.write(\"============\\n\")\n        writer.write(\n            getDirectoryStructure(\n                rootDirectory.toPath(),\n                rootDirectory.toPath(),\n                excludeMatchers,\n                includeMatchers\n            )\n        )\n        writer.write(\"\\n\")\n\n        // Write file contents\n        rootDirectory.walkTopDown()\n            .filter {\n                it.isFile \u0026\u0026\n                        it.absolutePath != outputFile.absolutePath \u0026\u0026\n                        !isExcluded(it.toPath(), rootDirectory.toPath(), excludeMatchers, includeMatchers)\n            }\n            .forEach { file -\u003e\n                writer.write(\"============\\n\")\n                writer.write(\"${file.name} : ${file.absolutePath}\\n\")\n                writer.write(\"============\\n\")\n                val content = file.readText()\n                writer.write(content)\n                writer.write(\"\\n\\n\")\n\n                fileCount++\n                totalLines += content.lineSequence().count()\n                totalWords += content.split(Regex(\"\\\\s+\")).count()\n            }\n\n        // Count directories excluding the root\n        directoryCount = rootDirectory.walkTopDown()\n            .filter {\n                it.isDirectory \u0026\u0026\n                        it != rootDirectory \u0026\u0026\n                        !isExcluded(it.toPath(), rootDirectory.toPath(), excludeMatchers, includeMatchers)\n            }\n            .count()\n\n        // Write summary\n        writer.write(\"========\\n\")\n        writer.write(\"Summary\\n\")\n        writer.write(\"========\\n\")\n        writer.write(\"Repository: ${rootDirectory.name}\\n\")\n        writer.write(\"Files analyzed: $fileCount\\n\")\n        writer.write(\"Directories analyzed: $directoryCount\\n\")\n        writer.write(\"Total lines of content: $totalLines\\n\")\n        writer.write(\"Total words: $totalWords\\n\")\n        if (excludePatternsInput.isNotEmpty()) {\n            writer.write(\"Excluded/Inclusion patterns:\\n\")\n            excludePatternsInput.forEach { pattern -\u003e\n                writer.write(\"- $pattern\\n\")\n            }\n        }\n    }\n\n    println(\"Merged content has been written to: ${outputFile.absolutePath}\")\n}\n\n/**\n * Adjusts the pattern to ensure directories are fully excluded by appending '**' if needed.\n */\nfun adjustPattern(pattern: String): String {\n    return if (pattern.endsWith(\"/\")) {\n        \"${pattern}**\"\n    } else {\n        pattern\n    }\n}\n\n/**\n * Generates a directory structure string similar to the `tree` command,\n * respecting the exclusion and inclusion patterns.\n */\nfun getDirectoryStructure(\n    currentPath: java.nio.file.Path,\n    rootPath: java.nio.file.Path,\n    excludeMatchers: List\u003cPathMatcher\u003e,\n    includeMatchers: List\u003cPathMatcher\u003e,\n    prefix: String = \"\"\n): String {\n    val builder = StringBuilder()\n    val files = currentPath.toFile().listFiles()?.sortedWith(compareBy({ !it.isDirectory }, { it.name }))\n        ?: return builder.toString()\n\n    files.forEachIndexed { index, file -\u003e\n        val isLast = index == files.lastIndex\n        val branch = if (isLast) \"└── \" else \"├── \"\n        val newPrefix = prefix + branch\n        val childPrefix = prefix + if (isLast) \"    \" else \"│   \"\n\n        // Get the relative path from the root directory\n        val relativePath = rootPath.relativize(file.toPath())\n\n        if (isExcluded(file.toPath(), rootPath, excludeMatchers, includeMatchers)) {\n            // Skip excluded files/directories\n            return@forEachIndexed\n        }\n\n        builder.append(\"$newPrefix${file.name}\\n\")\n        if (file.isDirectory) {\n            builder.append(\n                getDirectoryStructure(\n                    file.toPath(),\n                    rootPath,\n                    excludeMatchers,\n                    includeMatchers,\n                    childPrefix\n                )\n            )\n        }\n    }\n    return builder.toString()\n}\n\n/**\n * Determines whether a given path should be excluded based on the excludeMatchers and includeMatchers.\n * Inclusion patterns (!patterns) override exclusion patterns.\n */\nfun isExcluded(\n    path: java.nio.file.Path,\n    rootPath: java.nio.file.Path,\n    excludeMatchers: List\u003cPathMatcher\u003e,\n    includeMatchers: List\u003cPathMatcher\u003e\n): Boolean {\n    val relativePath = rootPath.relativize(path).toString().replace(File.separatorChar, '/')\n\n    // Check inclusion patterns first\n    if (includeMatchers.any { matcher -\u003e matcher.matches(FileSystems.getDefault().getPath(relativePath)) }) {\n        return false\n    }\n\n    // Then check exclusion patterns\n    return excludeMatchers.any { matcher -\u003e matcher.matches(FileSystems.getDefault().getPath(relativePath)) }\n}\n\n========\nSummary\n========\nRepository: 1fileKt\nFiles analyzed: 4\nDirectories analyzed: 10\nTotal lines of content: 219\nTotal words: 591\nExcluded/Inclusion patterns:\n- merged_content.md\n- **/build/\n- build/\n- gradlew\n- gradlew.bat\n- .gradle/\n- gradle/\n- **/resources\n- .idea/\n- .kotlin/\n- .gitignore\n- .git/\n- .git\n- *.iws\n- *.iml\n- *.ipr\n- out/\n- **/src/main/**/out/\n- **/src/test/**/out/\n- *.classpath\n- *.factorypath\n- .apt_generated\n- .project\n- .settings\n- .springBeans\n- .sts4-cache\n- bin/\n- **/src/main/**/bin/\n- **/src/test/**/bin/\n- nbproject/private/\n- nbbuild/\n- dist/\n- nbdist/\n- .nb-gradle/\n- .vscode/\n- .DS_Store\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fch8n%2F1filekt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fch8n%2F1filekt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fch8n%2F1filekt/lists"}