├── .aegir.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── scripts └── node-globals.js ├── src ├── index.js ├── resolver.js ├── util.js └── util │ ├── commit.js │ ├── tag.js │ ├── tree.js │ └── util.js └── test ├── fixtures ├── 0a1690e0640a212aafed1824eb208ffddab1789b ├── 0faccf822badf55f15fb0c3f4122fa13798f769e ├── 19f0805d8de36b6442e8c573074112ba72ad6780 ├── 42fd8d7404f5127314e248b2cbbe1423f12faeb9 ├── 4b271beec86978454072b632f382c6ccb3938a45 ├── 4d5e7ac145aaf440600dd06a97e8cc65f8acd4dc ├── 5af4dc18899e8ac95904eaf2b4abf1a2ca5e1507 ├── 70a3540bd51658ab564806785d5516a4e89b6450 ├── 7ffd1401f599c70364eda431d29363e037b2c92c ├── 802992c4220de19a90767f3000a79a31b98d0df7 ├── 832b4a8497de78248f70c06e0f06e785a74fea4c ├── 88a72947d8b4f0ab7185389efcdd5dace4643e04 ├── 933b7583b7767b07ea4cf242c1be29162eb8bb85 ├── 9f358a4addefcab294b83e4282bfef1f9625a249 ├── README.md ├── a0f06ca3cdb1e6e7f603794ef1cd9f9867f85551 ├── b1c46e7c32ff56e56a3da52be375348a664650ba ├── cf461f783732a8aa5f7d8679e112bd4c876aa19b ├── d52e70c9e34ac03cdf77f46aec388c2f9574bd93 ├── ed19ea7ea03ecd036c653b9c4cba16df71424a60 ├── ee048050d16bc428c4faef1074b740866ad553bb ├── f5227cbd32973ec90f48f2547e6fe16c80b92bd5 ├── fa59b93c6ce9db82ce57de9046eb738e9f3c0952 ├── fc80daf21bb484cfd42ad4ed4d17da48638199ea ├── ffef5350b6f8762cc6272b0255e968f50b6577ed ├── objects.json └── update.sh ├── mod.spec.js ├── parse.spec.js ├── resolver.spec.js └── util.spec.js /.aegir.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | 5 | const esbuild = { 6 | // this will inject all the named exports from 'node-globals.js' as globals 7 | inject: [path.join(__dirname, 'scripts/node-globals.js')], 8 | plugins: [ 9 | { 10 | name: 'node built ins', // this will make the bundler resolve node builtins to the respective browser polyfill 11 | setup (build) { 12 | build.onResolve({ filter: /^stream$/ }, () => { 13 | return { path: require.resolve('readable-stream') } 14 | }) 15 | build.onResolve({ filter: /^zlib$/ }, () => { 16 | return { path: require.resolve('browserify-zlib') } 17 | }) 18 | } 19 | } 20 | ] 21 | } 22 | 23 | /** @type {import('aegir').PartialOptions} */ 24 | module.exports = { 25 | test: { 26 | browser: { 27 | config: { 28 | buildConfig: esbuild 29 | } 30 | } 31 | }, 32 | build: { 33 | config: esbuild 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | yarn.lock 2 | docs 3 | **/node_modules/ 4 | **/*.log 5 | test/repo-tests* 6 | **/bundle.js 7 | 8 | # Logs 9 | logs 10 | *.log 11 | 12 | coverage 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | build 32 | 33 | # Dependency directory 34 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 35 | node_modules 36 | 37 | lib 38 | dist 39 | test/test-data/go-ipfs-repo/LOCK 40 | test/test-data/go-ipfs-repo/LOG 41 | test/test-data/go-ipfs-repo/LOG.old 42 | 43 | # while testing npm5 44 | package-lock.json 45 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # This is a copy of `.gitignore` without ignoring `dist`, please keep it in sync 2 | 3 | yarn.lock 4 | docs 5 | **/node_modules/ 6 | **/*.log 7 | test/repo-tests* 8 | **/bundle.js 9 | 10 | # Logs 11 | logs 12 | *.log 13 | 14 | coverage 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | build 34 | 35 | # Dependency directory 36 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 37 | node_modules 38 | 39 | lib 40 | 41 | test/test-data/go-ipfs-repo/LOCK 42 | test/test-data/go-ipfs-repo/LOG 43 | test/test-data/go-ipfs-repo/LOG.old 44 | 45 | # while testing npm5 46 | package-lock.json 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: npm 3 | stages: 4 | - check 5 | - test 6 | - cov 7 | 8 | node_js: 9 | - 'lts/*' 10 | - 'node' 11 | 12 | os: 13 | - linux 14 | - osx 15 | - windows 16 | 17 | script: npx nyc -s npm run test:node -- --bail 18 | after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov 19 | 20 | jobs: 21 | include: 22 | - stage: check 23 | script: 24 | - npx aegir dep-check 25 | - npm run lint 26 | 27 | - stage: test 28 | name: chrome 29 | addons: 30 | chrome: stable 31 | script: npx aegir test -t browser -t webworker 32 | 33 | - stage: test 34 | name: firefox 35 | addons: 36 | firefox: latest 37 | script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless 38 | 39 | notifications: 40 | email: false 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.6.6](https://github.com/ipld/js-ipld-git/compare/v0.6.5...v0.6.6) (2021-08-24) 2 | 3 | 4 | 5 | ## [0.6.5](https://github.com/ipld/js-ipld-git/compare/v0.6.4...v0.6.5) (2021-08-11) 6 | 7 | 8 | 9 | ## [0.6.4](https://github.com/ipld/js-ipld-git/compare/v0.6.1...v0.6.4) (2021-03-03) 10 | 11 | 12 | 13 | ## [0.6.3](https://github.com/ipld/js-ipld-git/compare/v0.6.1...v0.6.3) (2021-03-03) 14 | 15 | 16 | 17 | ## [0.6.2](https://github.com/ipld/js-ipld-git/compare/v0.6.1...v0.6.2) (2021-03-03) 18 | 19 | 20 | 21 | 22 | ## [0.6.1](https://github.com/ipld/js-ipld-git/compare/v0.6.0...v0.6.1) (2020-08-05) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * convert output of multihash.decode to buffer ([20dd68f](https://github.com/ipld/js-ipld-git/commit/20dd68f)) 28 | 29 | 30 | 31 | 32 | # [0.6.0](https://github.com/ipld/js-ipld-git/compare/v0.5.3...v0.6.0) (2020-08-04) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * replace node buffers with uint8arrays ([#70](https://github.com/ipld/js-ipld-git/issues/70)) ([8c999ba](https://github.com/ipld/js-ipld-git/commit/8c999ba)) 38 | 39 | 40 | ### BREAKING CHANGES 41 | 42 | * - `util.serialize` returns a `Uint8Array` 43 | - `util.cid` returns `CID`s with a breaking API change - see https://github.com/multiformats/js-cid/pull/117 for changes 44 | 45 | 46 | 47 | 48 | ## [0.5.3](https://github.com/ipld/js-ipld-git/compare/v0.5.2...v0.5.3) (2020-07-24) 49 | 50 | 51 | 52 | 53 | ## [0.5.2](https://github.com/ipld/js-ipld-git/compare/v0.5.1...v0.5.2) (2020-06-19) 54 | 55 | 56 | ### Bug Fixes 57 | 58 | * multihashes does not export default lengths any more ([4f85c53](https://github.com/ipld/js-ipld-git/commit/4f85c53)), closes [/github.com/multiformats/js-multihash/pull/76#issuecomment-646561123](https://github.com//github.com/multiformats/js-multihash/pull/76/issues/issuecomment-646561123) 59 | * **package:** update cids to version 0.8.0 ([9da8893](https://github.com/ipld/js-ipld-git/commit/9da8893)) 60 | 61 | 62 | 63 | 64 | ## [0.5.1](https://github.com/ipld/js-ipld-git/compare/v0.5.0...v0.5.1) (2020-01-13) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * **package:** update multicodec to version 1.0.0 ([6dbc3c8](https://github.com/ipld/js-ipld-git/commit/6dbc3c8)) 70 | * **package:** update multihashing-async to version 0.8.0 ([fcf7f6f](https://github.com/ipld/js-ipld-git/commit/fcf7f6f)) 71 | 72 | 73 | 74 | 75 | # [0.5.0](https://github.com/ipld/js-ipld-git/compare/v0.4.0...v0.5.0) (2019-05-10) 76 | 77 | 78 | ### Bug Fixes 79 | 80 | * **package:** update cids to version 0.7.0 ([2d87c9e](https://github.com/ipld/js-ipld-git/commit/2d87c9e)) 81 | 82 | 83 | ### BREAKING CHANGES 84 | 85 | * **package:** Returned v1 CIDs now default to base32 encoding 86 | 87 | Previous versions returned a base58 encoded string when `toString()`/ 88 | `toBaseEncodedString()` was called on a CIDv1. It now returns a base32 89 | encoded string. 90 | 91 | 92 | 93 | 94 | # [0.4.0](https://github.com/ipld/js-ipld-git/compare/v0.3.0...v0.4.0) (2019-05-08) 95 | 96 | 97 | ### Bug Fixes 98 | 99 | * **package:** update cids to version 0.6.0 ([fe0ac8b](https://github.com/ipld/js-ipld-git/commit/fe0ac8b)) 100 | * **package:** update multihashing-async to version 0.6.0 ([784c464](https://github.com/ipld/js-ipld-git/commit/784c464)) 101 | 102 | 103 | ### Features 104 | 105 | * new IPLD Format API ([e39a7d9](https://github.com/ipld/js-ipld-git/commit/e39a7d9)) 106 | 107 | 108 | ### BREAKING CHANGES 109 | 110 | * The API is now async/await based 111 | 112 | There are numerous changes, the most significant one is that the API 113 | is no longer callback based, but it using async/await. 114 | 115 | For the full new API please see the [IPLD Formats spec]. 116 | 117 | [IPLD Formats spec]: https://github.com/ipld/interface-ipld-format 118 | 119 | 120 | 121 | 122 | # [0.3.0](https://github.com/ipld/js-ipld-git/compare/v0.2.3...v0.3.0) (2019-03-27) 123 | 124 | 125 | ### Bug Fixes 126 | 127 | * order tree directory entries correctly (fixes [#44](https://github.com/ipld/js-ipld-git/issues/44)) ([02be41f](https://github.com/ipld/js-ipld-git/commit/02be41f)) 128 | 129 | 130 | ### Features 131 | 132 | * use RFC3339 to format dates, fixes ipfs/go-ipld-git[#16](https://github.com/ipld/js-ipld-git/issues/16) ([#43](https://github.com/ipld/js-ipld-git/issues/43)) ([8a9f7cb](https://github.com/ipld/js-ipld-git/commit/8a9f7cb)) 133 | 134 | 135 | ### BREAKING CHANGES 136 | 137 | * Dates are now returned in ISO 8601/RFC3399 format 138 | 139 | 140 | 141 | 142 | ## [0.2.3](https://github.com/ipld/js-ipld-git/compare/v0.2.2...v0.2.3) (2019-01-18) 143 | 144 | 145 | ### Bug Fixes 146 | 147 | * **package:** update multicodec to version 0.4.0 ([c370777](https://github.com/ipld/js-ipld-git/commit/c370777)), closes [#34](https://github.com/ipld/js-ipld-git/issues/34) 148 | * browser bundle ([#39](https://github.com/ipld/js-ipld-git/issues/39)) ([d7d078f](https://github.com/ipld/js-ipld-git/commit/d7d078f)) 149 | 150 | 151 | 152 | 153 | ## [0.2.2](https://github.com/ipld/js-ipld-git/compare/v0.2.1...v0.2.2) (2018-10-12) 154 | 155 | 156 | ### Features 157 | 158 | * parse mergetags ([f2010df](https://github.com/ipld/js-ipld-git/commit/f2010df)) 159 | 160 | 161 | 162 | 163 | ## [0.2.1](https://github.com/ipld/js-ipld-git/compare/v0.2.0...v0.2.1) (2018-06-29) 164 | 165 | 166 | ### Bug Fixes 167 | 168 | * do not ignore cid.options ([#18](https://github.com/ipld/js-ipld-git/issues/18)) ([4641b63](https://github.com/ipld/js-ipld-git/commit/4641b63)) 169 | * pass serialized blob to util.cid ([#16](https://github.com/ipld/js-ipld-git/issues/16)) ([d8f8687](https://github.com/ipld/js-ipld-git/commit/d8f8687)) 170 | 171 | 172 | ### Features 173 | 174 | * add defaultHashAlg ([d0ccec3](https://github.com/ipld/js-ipld-git/commit/d0ccec3)) 175 | * add util.cid options ([#15](https://github.com/ipld/js-ipld-git/issues/15)) ([5ed9c74](https://github.com/ipld/js-ipld-git/commit/5ed9c74)) 176 | 177 | 178 | ### BREAKING CHANGES 179 | 180 | * the first argument is now the serialized output NOT the dag node. 181 | See https://github.com/ipld/interface-ipld-format/issues/32 182 | 183 | 184 | 185 | 186 | # [0.2.0](https://github.com/ipld/js-ipld-git/compare/v0.1.1...v0.2.0) (2018-02-12) 187 | 188 | 189 | ### Bug Fixes 190 | 191 | * use binary blobs directly ([334f2f0](https://github.com/ipld/js-ipld-git/commit/334f2f0)) 192 | 193 | 194 | ### BREAKING CHANGES 195 | 196 | * Everyone calling the functions of `resolve` need to 197 | pass in the binary data instead of an IPFS block. 198 | 199 | So if your input is an IPFS block, the code changes from 200 | 201 | resolver.resolve(block, path, (err, result) => {…} 202 | 203 | to 204 | 205 | resolver.resolve(block.data, path, (err, result) => {…} 206 | 207 | 208 | 209 | 210 | ## [0.1.1](https://github.com/ipld/js-ipld-git/compare/v0.1.0...v0.1.1) (2017-11-07) 211 | 212 | 213 | ### Bug Fixes 214 | 215 | * invalid signature parsing ([#6](https://github.com/ipld/js-ipld-git/issues/6)) ([b1f8bd4](https://github.com/ipld/js-ipld-git/commit/b1f8bd4)) 216 | 217 | 218 | 219 | 220 | # [0.1.0](https://github.com/ipld/js-ipld-git/compare/51a9b5e...v0.1.0) (2017-09-02) 221 | 222 | 223 | ### Bug Fixes 224 | 225 | * deps in package.json ([fece381](https://github.com/ipld/js-ipld-git/commit/fece381)) 226 | 227 | 228 | ### Features 229 | 230 | * v0.1.0 ([51a9b5e](https://github.com/ipld/js-ipld-git/commit/51a9b5e)) 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 IPLD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⛔️ DEPRECATED: This module is no longer maintained. It can be used with [multiformats](https://github.com/multiformats/js-multiformats) by wrapping it with [ipld-format-to-blockcodec](https://github.com/ipld/js-ipld-format-to-blockcodec) 2 | ====== 3 | 4 | # js-ipld-git 5 | 6 | [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) 7 | [![](https://img.shields.io/badge/project-IPLD-blue.svg?style=flat-square)](http://github.com/ipld/ipld) 8 | [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) 9 | [![Travis CI](https://flat.badgen.net/travis/ipld/js-ipld-git)](https://travis-ci.com/ipld/js-ipld-git) 10 | [![Coverage](https://coveralls.io/repos/github/ipld/js-ipld-git/badge.svg?branch=master)](https://coveralls.io/github/ipld/js-ipld-git?branch=master) 11 | [![](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) 12 | [![](https://david-dm.org/ipld/js-ipld-git.svg?style=flat-square)](https://david-dm.org/ipld/js-ipld-git) 13 | [![](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) [![Greenkeeper badge](https://badges.greenkeeper.io/ipld/js-ipld-git.svg)](https://greenkeeper.io/) 14 | ![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square) 15 | ![](https://img.shields.io/badge/Node.js-%3E%3D6.0.0-orange.svg?style=flat-square) 16 | 17 | > JavaScript implementation of the [IPLD spec](https://github.com/ipld/specs). 18 | 19 | ## Lead Maintainer 20 | 21 | [Volker Mische](https://github.com/vmx) 22 | 23 | ## Table of Contents 24 | 25 | - [js-ipld-git](#js-ipld-git) 26 | - [Lead Maintainer](#lead-maintainer) 27 | - [Table of Contents](#table-of-contents) 28 | - [Install](#install) 29 | - [npm](#npm) 30 | - [Use in Node.js](#use-in-nodejs) 31 | - [Use in a browser with browserify, webpack or any other bundler](#use-in-a-browser-with-browserify-webpack-or-any-other-bundler) 32 | - [Use in a browser Using a script tag](#use-in-a-browser-using-a-script-tag) 33 | - [Usage](#usage) 34 | - [Contribute](#contribute) 35 | - [License](#license) 36 | 37 | ## Install 38 | 39 | ### npm 40 | 41 | ```sh 42 | > npm install ipld-git 43 | ``` 44 | 45 | ### Use in Node.js 46 | 47 | ```JavaScript 48 | const IpldGit = require('ipld-git') 49 | ``` 50 | 51 | ### Use in a browser with browserify, webpack or any other bundler 52 | 53 | The code published to npm that gets loaded on require is in fact a ES5 transpiled version with the right shims added. This means that you can require it and use with your favourite bundler without having to adjust asset management process. 54 | 55 | ```JavaScript 56 | var IpldGit = require('ipld-git') 57 | ``` 58 | 59 | ### Use in a browser Using a script tag 60 | 61 | Loading this module through a script tag will make the `IpldGit` obj available in the global namespace. 62 | 63 | ```html 64 | 65 | 66 | 67 | ``` 68 | 69 | ## Usage 70 | 71 | ```JavaScript 72 | const IpldGit = require('ipld-git') 73 | const zlib = require('zlib') 74 | 75 | // `gitObject` is a Buffer containing a git object 76 | inflatedObject = zlib.inflateSync(gitObject) 77 | const dagNode = IpldGit.util.deserialize(inflatedObject) 78 | console.log(dagNode) 79 | ``` 80 | 81 | ## Contribute 82 | 83 | Feel free to join in. All welcome. Open an [issue](https://github.com/ipld/js-ipld-git/issues)! 84 | 85 | Check out our [contributing document](https://github.com/ipld/ipld/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to IPLD are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). 86 | 87 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. 88 | 89 | ## License 90 | 91 | [MIT](LICENSE) 92 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ipld-git", 3 | "version": "0.6.6", 4 | "description": "JavaScript Implementation of Git IPLD format", 5 | "leadMaintainer": "Volker Mische ", 6 | "main": "src/index.js", 7 | "scripts": { 8 | "test": "aegir test", 9 | "test:browser": "aegir test --target browser", 10 | "test:node": "aegir test --target node", 11 | "lint": "aegir lint", 12 | "release": "aegir release", 13 | "release-minor": "aegir release --type minor", 14 | "release-major": "aegir release --type major", 15 | "build": "aegir build" 16 | }, 17 | "pre-push": [ 18 | "lint", 19 | "test" 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/ipld/js-ipld-git.git" 24 | }, 25 | "keywords": [ 26 | "IPFS" 27 | ], 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/ipld/js-ipld-git/issues" 31 | }, 32 | "engines": { 33 | "node": ">=6.0.0", 34 | "npm": ">=3.0.0" 35 | }, 36 | "homepage": "https://github.com/ipld/js-ipld-git", 37 | "dependencies": { 38 | "buffer": "^6.0.3", 39 | "cids": "^1.0.0", 40 | "multicodec": "^3.0.1", 41 | "multihashing-async": "^2.0.1", 42 | "smart-buffer": "^4.1.0", 43 | "strftime": "^0.10.0", 44 | "uint8arrays": "^3.0.0" 45 | }, 46 | "devDependencies": { 47 | "aegir": "^31.0.1", 48 | "assert": "^2.0.0", 49 | "browserify-zlib": "^0.2.0", 50 | "events": "^3.3.0", 51 | "readable-stream": "^3.6.0" 52 | }, 53 | "contributors": [ 54 | "Volker Mische ", 55 | "David Dias ", 56 | "achingbrain ", 57 | "Łukasz Magiera ", 58 | "Richard Schneider ", 59 | "Jonah Weissman ", 60 | "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ ", 61 | "Sameer Puri <11097096+sameer@users.noreply.github.com>", 62 | "Vasco Santos ", 63 | "phillmac ", 64 | "Alan Shaw " 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /scripts/node-globals.js: -------------------------------------------------------------------------------- 1 | // file: node-globals.js 2 | // @ts-nocheck 3 | export const { Buffer } = require('buffer') 4 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.util = require('./util.js') 4 | exports.resolver = require('./resolver.js') 5 | exports.codec = exports.util.codec 6 | exports.defaultHashAlg = exports.util.defaultHashAlg 7 | -------------------------------------------------------------------------------- /src/resolver.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const CID = require('cids') 4 | const util = require('./util') 5 | 6 | /** 7 | * Resolves a path within a Git block. 8 | * 9 | * Returns the value or a link and the partial mising path. This way the 10 | * IPLD Resolver can fetch the link and continue to resolve. 11 | * 12 | * @param {Uint8Array} binaryBlob - Binary representation of a Git block 13 | * @param {string} [path='/'] - Path that should be resolved 14 | */ 15 | function resolve (binaryBlob, path) { 16 | let node = util.deserialize(binaryBlob) 17 | 18 | const parts = path.split('/').filter(Boolean) 19 | while (parts.length) { 20 | const key = parts.shift() 21 | if (node[key] === undefined) { 22 | throw new Error(`Object has no property '${key}'`) 23 | } 24 | 25 | node = node[key] 26 | if (CID.isCID(node)) { 27 | return { 28 | value: node, 29 | remainderPath: parts.join('/') 30 | } 31 | } 32 | } 33 | 34 | return { 35 | value: node, 36 | remainderPath: '' 37 | } 38 | } 39 | 40 | function * traverse (node, path) { 41 | // Traverse only objects and arrays 42 | if (node instanceof Uint8Array || CID.isCID(node) || typeof node === 'string' || 43 | node === null) { 44 | return 45 | } 46 | for (const item of Object.keys(node)) { 47 | const nextpath = path === undefined ? item : path + '/' + item 48 | yield nextpath 49 | yield * traverse(node[item], nextpath) 50 | } 51 | } 52 | 53 | /** 54 | * Return all available paths of a block. 55 | * 56 | * @generator 57 | * @param {Uint8Array} binaryBlob - Binary representation of a Bitcoin block 58 | * @yields {string} - A single path 59 | */ 60 | function * tree (binaryBlob) { 61 | const node = util.deserialize(binaryBlob) 62 | 63 | yield * traverse(node) 64 | } 65 | 66 | module.exports = { 67 | resolve, 68 | tree 69 | } 70 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const multihashing = require('multihashing-async') 4 | const CID = require('cids') 5 | const multicodec = require('multicodec') 6 | const { Buffer } = require('buffer') 7 | const { toString: uint8ArrayToString } = require('uint8arrays/to-string') 8 | 9 | const gitUtil = require('./util/util') 10 | 11 | const commit = require('./util/commit') 12 | const tag = require('./util/tag') 13 | const tree = require('./util/tree') 14 | 15 | const codec = multicodec.GIT_RAW 16 | const defaultHashAlg = multicodec.SHA1 17 | 18 | /** 19 | * Serialize internal representation into a binary Git block. 20 | * 21 | * @param {GitBlock} dagNode - Internal representation of a Git block 22 | * @returns {Uint8Array} 23 | */ 24 | function serialize (dagNode) { 25 | if (dagNode === null) { 26 | throw new Error('dagNode passed to serialize was null') 27 | } 28 | 29 | if (dagNode instanceof Uint8Array) { 30 | if (uint8ArrayToString(dagNode.slice(0, 4)) === 'blob') { 31 | return dagNode 32 | } else { 33 | throw new Error('unexpected dagNode passed to serialize') 34 | } 35 | } 36 | 37 | switch (dagNode.gitType) { 38 | case 'commit': 39 | return commit.serialize(dagNode) 40 | case 'tag': 41 | return tag.serialize(dagNode) 42 | default: 43 | // assume tree as a file named 'type' is legal 44 | return tree.serialize(dagNode) 45 | } 46 | } 47 | 48 | /** 49 | * Deserialize Git block into the internal representation. 50 | * 51 | * @param {Uint8Array} data - Binary representation of a Git block. 52 | */ 53 | function deserialize (data) { 54 | if (!Buffer.isBuffer(data)) { 55 | data = Buffer.from(data.buffer, data.byteOffset, data.byteLength) 56 | } 57 | 58 | const headLen = gitUtil.find(data, 0) 59 | const head = data.slice(0, headLen).toString() 60 | const typeLen = head.match(/([^ ]+) (\d+)/) 61 | if (!typeLen) { 62 | throw new Error('invalid object header') 63 | } 64 | 65 | switch (typeLen[1]) { 66 | case 'blob': 67 | return data 68 | case 'commit': 69 | return commit.deserialize(data.slice(headLen + 1)) 70 | case 'tag': 71 | return tag.deserialize(data.slice(headLen + 1)) 72 | case 'tree': 73 | return tree.deserialize(data.slice(headLen + 1)) 74 | default: 75 | throw new Error('unknown object type ' + typeLen[1]) 76 | } 77 | } 78 | 79 | /** 80 | * Calculate the CID of the binary blob. 81 | * 82 | * @param {Object} binaryBlob - Encoded IPLD Node 83 | * @param {Object} [userOptions] - Options to create the CID 84 | * @param {number} [userOptions.cidVersion=1] - CID version number 85 | * @param {string} [userOptions.hashAlg] - Defaults to the defaultHashAlg of the format 86 | */ 87 | async function cid (binaryBlob, userOptions) { 88 | const defaultOptions = { cidVersion: 1, hashAlg: defaultHashAlg } 89 | const options = Object.assign(defaultOptions, userOptions) 90 | 91 | const multihash = await multihashing(binaryBlob, options.hashAlg) 92 | const codecName = multicodec.getNameFromCode(codec) 93 | const cid = new CID(options.cidVersion, codecName, multihash) 94 | 95 | return cid 96 | } 97 | 98 | module.exports = { 99 | codec, 100 | defaultHashAlg, 101 | serialize, 102 | deserialize, 103 | cid 104 | } 105 | -------------------------------------------------------------------------------- /src/util/commit.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const SmartBuffer = require('smart-buffer').SmartBuffer 4 | const { Buffer } = require('buffer') 5 | const gitUtil = require('./util') 6 | 7 | function serialize (dagNode) { 8 | const lines = [] 9 | lines.push('tree ' + gitUtil.cidToSha(dagNode.tree).toString('hex')) 10 | dagNode.parents.forEach((parent) => { 11 | lines.push('parent ' + gitUtil.cidToSha(parent).toString('hex')) 12 | }) 13 | lines.push('author ' + gitUtil.serializePersonLine(dagNode.author)) 14 | lines.push('committer ' + gitUtil.serializePersonLine(dagNode.committer)) 15 | if (dagNode.encoding) { 16 | lines.push('encoding ' + dagNode.encoding) 17 | } 18 | if (dagNode.mergetag) { 19 | dagNode.mergetag.forEach(tag => { 20 | lines.push('mergetag object ' + gitUtil.cidToSha(tag.object).toString('hex')) 21 | lines.push(tag.text) 22 | }) 23 | } 24 | if (dagNode.signature) { 25 | lines.push('gpgsig -----BEGIN PGP SIGNATURE-----') 26 | lines.push(dagNode.signature.text) 27 | } 28 | lines.push('') 29 | lines.push(dagNode.message) 30 | 31 | const data = lines.join('\n') 32 | 33 | const outBuf = new SmartBuffer() 34 | outBuf.writeString('commit ') 35 | outBuf.writeString(data.length.toString()) 36 | outBuf.writeUInt8(0) 37 | outBuf.writeString(data) 38 | return outBuf.toBuffer() 39 | } 40 | 41 | function deserialize (data) { 42 | const lines = data.toString().split('\n') 43 | const res = { gitType: 'commit', parents: [] } 44 | 45 | for (let line = 0; line < lines.length; line++) { 46 | const m = lines[line].match(/^([^ ]+) (.+)$/) 47 | if (!m) { 48 | if (lines[line] !== '') { 49 | throw new Error('Invalid commit line ' + line) 50 | } 51 | res.message = lines.slice(line + 1).join('\n') 52 | break 53 | } 54 | 55 | const key = m[1] 56 | const value = m[2] 57 | switch (key) { 58 | case 'tree': 59 | res.tree = gitUtil.shaToCid(Buffer.from(value, 'hex')) 60 | break 61 | case 'committer': 62 | res.committer = gitUtil.parsePersonLine(value) 63 | break 64 | case 'author': 65 | res.author = gitUtil.parsePersonLine(value) 66 | break 67 | case 'parent': 68 | res.parents.push(gitUtil.shaToCid(Buffer.from(value, 'hex'))) 69 | break 70 | case 'gpgsig': { 71 | if (value !== '-----BEGIN PGP SIGNATURE-----') { 72 | throw new Error('Invalid commit line ' + line) 73 | } 74 | res.signature = {} 75 | 76 | const startLine = line 77 | for (; line < lines.length - 1; line++) { 78 | if (lines[line + 1][0] !== ' ') { 79 | res.signature.text = lines.slice(startLine + 1, line + 1).join('\n') 80 | break 81 | } 82 | } 83 | break 84 | } 85 | case 'mergetag': { 86 | const mt = value.match(/^object ([0-9a-f]{40})$/) 87 | if (!mt) { 88 | throw new Error('Invalid commit line ' + line) 89 | } 90 | 91 | const tag = { object: gitUtil.shaToCid(Buffer.from(mt[1], 'hex')) } 92 | 93 | const startLine = line 94 | for (; line < lines.length - 1; line++) { 95 | if (lines[line + 1][0] !== ' ') { 96 | tag.text = lines.slice(startLine + 1, line + 1).join('\n') 97 | break 98 | } 99 | } 100 | 101 | if (!res.mergetag) { 102 | res.mergetag = [] 103 | } 104 | 105 | res.mergetag.push(tag) 106 | } 107 | 108 | break 109 | default: 110 | res[key] = value 111 | } 112 | } 113 | 114 | Object.defineProperty(res, 'gitType', { enumerable: false }) 115 | 116 | return res 117 | } 118 | 119 | module.exports = { 120 | serialize, 121 | deserialize 122 | } 123 | -------------------------------------------------------------------------------- /src/util/tag.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const SmartBuffer = require('smart-buffer').SmartBuffer 4 | const { Buffer } = require('buffer') 5 | const gitUtil = require('./util') 6 | 7 | function serialize (dagNode) { 8 | const lines = [] 9 | lines.push('object ' + gitUtil.cidToSha(dagNode.object).toString('hex')) 10 | lines.push('type ' + dagNode.type) 11 | lines.push('tag ' + dagNode.tag) 12 | if (dagNode.tagger !== null) { 13 | lines.push('tagger ' + gitUtil.serializePersonLine(dagNode.tagger)) 14 | } 15 | lines.push('') 16 | lines.push(dagNode.message) 17 | 18 | const data = lines.join('\n') 19 | 20 | const outBuf = new SmartBuffer() 21 | outBuf.writeString('tag ') 22 | outBuf.writeString(data.length.toString()) 23 | outBuf.writeUInt8(0) 24 | outBuf.writeString(data) 25 | return outBuf.toBuffer() 26 | } 27 | 28 | function deserialize (data) { 29 | const lines = data.toString().split('\n') 30 | const res = { gitType: 'tag' } 31 | 32 | for (let line = 0; line < lines.length; line++) { 33 | const m = lines[line].match(/^([^ ]+) (.+)$/) 34 | if (m === null) { 35 | if (lines[line] !== '') { 36 | throw new Error('Invalid tag line ' + line) 37 | } 38 | res.message = lines.slice(line + 1).join('\n') 39 | break 40 | } 41 | 42 | const key = m[1] 43 | const value = m[2] 44 | switch (key) { 45 | case 'object': 46 | res.object = gitUtil.shaToCid(Buffer.from(value, 'hex')) 47 | break 48 | case 'tagger': 49 | res.tagger = gitUtil.parsePersonLine(value) 50 | break 51 | case 'tag': 52 | res.tag = value 53 | break 54 | case 'type': 55 | res.type = value 56 | break 57 | default: 58 | res[key] = value 59 | } 60 | } 61 | 62 | Object.defineProperty(res, 'gitType', { enumerable: false }) 63 | 64 | return res 65 | } 66 | 67 | module.exports = { 68 | serialize, 69 | deserialize 70 | } 71 | -------------------------------------------------------------------------------- /src/util/tree.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const SmartBuffer = require('smart-buffer').SmartBuffer 4 | const gitUtil = require('./util') 5 | 6 | function serialize (dagNode) { 7 | const entries = [] 8 | Object.keys(dagNode).forEach((name) => { 9 | entries.push([name, dagNode[name]]) 10 | }) 11 | entries.sort((a, b) => { 12 | const aName = a[0] + (a[1].mode === '40000' ? '/' : '') 13 | const bName = b[0] + (b[1].mode === '40000' ? '/' : '') 14 | return aName > bName ? 1 : -1 15 | }) 16 | const buf = new SmartBuffer() 17 | entries.forEach((entry) => { 18 | buf.writeStringNT(entry[1].mode + ' ' + entry[0]) 19 | buf.writeBuffer(gitUtil.cidToSha(entry[1].hash)) 20 | }) 21 | 22 | const outBuf = new SmartBuffer() 23 | outBuf.writeString('tree ') 24 | outBuf.writeString(buf.length.toString()) 25 | outBuf.writeUInt8(0) 26 | outBuf.writeBuffer(buf.toBuffer()) 27 | return outBuf.toBuffer() 28 | } 29 | 30 | function deserialize (data) { 31 | const res = {} 32 | const buf = SmartBuffer.fromBuffer(data, 'utf8') 33 | 34 | for (;;) { 35 | const modeName = buf.readStringNT() 36 | if (modeName === '') { 37 | break 38 | } 39 | 40 | const hash = buf.readBuffer(gitUtil.SHA1_LENGTH) 41 | const modNameMatched = modeName.match(/^(\d+) (.+)$/) 42 | if (!modNameMatched) { 43 | throw new Error('invalid file mode/name') 44 | } 45 | 46 | if (res[modNameMatched[2]]) { 47 | throw new Error('duplicate file in tree') 48 | } 49 | 50 | res[modNameMatched[2]] = { 51 | mode: modNameMatched[1], 52 | hash: gitUtil.shaToCid(hash) 53 | } 54 | } 55 | 56 | return res 57 | } 58 | 59 | module.exports = { 60 | serialize, 61 | deserialize 62 | } 63 | -------------------------------------------------------------------------------- /src/util/util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const multihash = require('multihashing-async').multihash 4 | const CID = require('cids') 5 | const strftime = require('strftime') 6 | const { Buffer } = require('buffer') 7 | 8 | const SHA1_LENGTH = 20 9 | 10 | function find (buf, byte) { 11 | for (let i = 0; i < buf.length; i++) { 12 | if (buf[i] === byte) { 13 | return i 14 | } 15 | } 16 | return -1 17 | } 18 | 19 | const ISO_8601_STRICT = '%FT%T%:z' 20 | const TIMESTAMP_WITH_OFFSET = '%s %z' 21 | 22 | const timestampWithOffsetToISOStrict = (timestamp, offset) => strftime.timezone(offset)(ISO_8601_STRICT, new Date(timestamp * 1000)) 23 | 24 | const isoStrictToTimestampWithOffset = (isoString) => { 25 | const matched = isoString.match(/([+-]\d{2}:\d{2})/) 26 | const offset = matched === null ? '+0000' : (matched[0].slice(0, 3) + matched[0].slice(4)) 27 | return strftime.timezone(offset)(TIMESTAMP_WITH_OFFSET, new Date(isoString)) 28 | } 29 | 30 | function parsePersonLine (line) { 31 | const matched = line.match(/^(([^<]+)\s)?\s?<([^>]+)>\s?(?:(\d+)\s([+-]\d+))?$/) 32 | if (matched === null) { 33 | return null 34 | } 35 | 36 | return { 37 | name: matched[2], 38 | email: matched[3], 39 | date: matched[4] && matched[5] && timestampWithOffsetToISOStrict(parseInt(matched[4]), matched[5]) 40 | } 41 | } 42 | 43 | function serializePersonLine (node) { 44 | const parts = [] 45 | if (node.name) { 46 | parts.push(node.name) 47 | } 48 | parts.push('<' + node.email + '>') 49 | if (node.date) { 50 | parts.push(isoStrictToTimestampWithOffset(node.date)) 51 | } 52 | 53 | return parts.join(' ') 54 | } 55 | 56 | function shaToCid (buf) { 57 | const mh = multihash.encode(buf, 'sha1') 58 | return new CID(1, 'git-raw', mh) 59 | } 60 | 61 | function cidToSha (cid) { 62 | const mh = multihash.decode(cid.multihash) 63 | if (mh.name !== 'sha1') { 64 | return null 65 | } 66 | 67 | return Buffer.from(mh.digest.buffer, mh.digest.byteOffset, mh.digest.byteLength) 68 | } 69 | 70 | module.exports = { 71 | SHA1_LENGTH, 72 | find, 73 | parsePersonLine, 74 | serializePersonLine, 75 | shaToCid, 76 | cidToSha 77 | } 78 | -------------------------------------------------------------------------------- /test/fixtures/0a1690e0640a212aafed1824eb208ffddab1789b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/0a1690e0640a212aafed1824eb208ffddab1789b -------------------------------------------------------------------------------- /test/fixtures/0faccf822badf55f15fb0c3f4122fa13798f769e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/0faccf822badf55f15fb0c3f4122fa13798f769e -------------------------------------------------------------------------------- /test/fixtures/19f0805d8de36b6442e8c573074112ba72ad6780: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/19f0805d8de36b6442e8c573074112ba72ad6780 -------------------------------------------------------------------------------- /test/fixtures/42fd8d7404f5127314e248b2cbbe1423f12faeb9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/42fd8d7404f5127314e248b2cbbe1423f12faeb9 -------------------------------------------------------------------------------- /test/fixtures/4b271beec86978454072b632f382c6ccb3938a45: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/4b271beec86978454072b632f382c6ccb3938a45 -------------------------------------------------------------------------------- /test/fixtures/4d5e7ac145aaf440600dd06a97e8cc65f8acd4dc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/4d5e7ac145aaf440600dd06a97e8cc65f8acd4dc -------------------------------------------------------------------------------- /test/fixtures/5af4dc18899e8ac95904eaf2b4abf1a2ca5e1507: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/5af4dc18899e8ac95904eaf2b4abf1a2ca5e1507 -------------------------------------------------------------------------------- /test/fixtures/70a3540bd51658ab564806785d5516a4e89b6450: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/70a3540bd51658ab564806785d5516a4e89b6450 -------------------------------------------------------------------------------- /test/fixtures/7ffd1401f599c70364eda431d29363e037b2c92c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/7ffd1401f599c70364eda431d29363e037b2c92c -------------------------------------------------------------------------------- /test/fixtures/802992c4220de19a90767f3000a79a31b98d0df7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/802992c4220de19a90767f3000a79a31b98d0df7 -------------------------------------------------------------------------------- /test/fixtures/832b4a8497de78248f70c06e0f06e785a74fea4c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/832b4a8497de78248f70c06e0f06e785a74fea4c -------------------------------------------------------------------------------- /test/fixtures/88a72947d8b4f0ab7185389efcdd5dace4643e04: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/88a72947d8b4f0ab7185389efcdd5dace4643e04 -------------------------------------------------------------------------------- /test/fixtures/933b7583b7767b07ea4cf242c1be29162eb8bb85: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/933b7583b7767b07ea4cf242c1be29162eb8bb85 -------------------------------------------------------------------------------- /test/fixtures/9f358a4addefcab294b83e4282bfef1f9625a249: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/9f358a4addefcab294b83e4282bfef1f9625a249 -------------------------------------------------------------------------------- /test/fixtures/README.md: -------------------------------------------------------------------------------- 1 | Generated with https://github.com/ipfs/go-ipld-git/blob/master/make-test-repo.sh 2 | 3 | To update the test objects: 4 | * make sure you have `jq` installed 5 | * cd into this directory 6 | * run `./update.sh` 7 | 8 | The script will download test data from https://github.com/ipfs/go-ipld-git and extract it here 9 | 10 | To add/change test objects, you'll need to change https://github.com/ipfs/go-ipld-git/blob/master/make-test-repo.sh, 11 | and regenerate testdata there. 12 | -------------------------------------------------------------------------------- /test/fixtures/a0f06ca3cdb1e6e7f603794ef1cd9f9867f85551: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/a0f06ca3cdb1e6e7f603794ef1cd9f9867f85551 -------------------------------------------------------------------------------- /test/fixtures/b1c46e7c32ff56e56a3da52be375348a664650ba: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/b1c46e7c32ff56e56a3da52be375348a664650ba -------------------------------------------------------------------------------- /test/fixtures/cf461f783732a8aa5f7d8679e112bd4c876aa19b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/cf461f783732a8aa5f7d8679e112bd4c876aa19b -------------------------------------------------------------------------------- /test/fixtures/d52e70c9e34ac03cdf77f46aec388c2f9574bd93: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/d52e70c9e34ac03cdf77f46aec388c2f9574bd93 -------------------------------------------------------------------------------- /test/fixtures/ed19ea7ea03ecd036c653b9c4cba16df71424a60: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/ed19ea7ea03ecd036c653b9c4cba16df71424a60 -------------------------------------------------------------------------------- /test/fixtures/ee048050d16bc428c4faef1074b740866ad553bb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/ee048050d16bc428c4faef1074b740866ad553bb -------------------------------------------------------------------------------- /test/fixtures/f5227cbd32973ec90f48f2547e6fe16c80b92bd5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/f5227cbd32973ec90f48f2547e6fe16c80b92bd5 -------------------------------------------------------------------------------- /test/fixtures/fa59b93c6ce9db82ce57de9046eb738e9f3c0952: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/fa59b93c6ce9db82ce57de9046eb738e9f3c0952 -------------------------------------------------------------------------------- /test/fixtures/fc80daf21bb484cfd42ad4ed4d17da48638199ea: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/fc80daf21bb484cfd42ad4ed4d17da48638199ea -------------------------------------------------------------------------------- /test/fixtures/ffef5350b6f8762cc6272b0255e968f50b6577ed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipld/js-ipld-git/c2830e25825d00178f761d7e871a6797e28f440d/test/fixtures/ffef5350b6f8762cc6272b0255e968f50b6577ed -------------------------------------------------------------------------------- /test/fixtures/objects.json: -------------------------------------------------------------------------------- 1 | [ 2 | "b1c46e7c32ff56e56a3da52be375348a664650ba", 3 | "ee048050d16bc428c4faef1074b740866ad553bb", 4 | "d52e70c9e34ac03cdf77f46aec388c2f9574bd93", 5 | "70a3540bd51658ab564806785d5516a4e89b6450", 6 | "0faccf822badf55f15fb0c3f4122fa13798f769e", 7 | "933b7583b7767b07ea4cf242c1be29162eb8bb85", 8 | "4d5e7ac145aaf440600dd06a97e8cc65f8acd4dc", 9 | "ed19ea7ea03ecd036c653b9c4cba16df71424a60", 10 | "cf461f783732a8aa5f7d8679e112bd4c876aa19b", 11 | "88a72947d8b4f0ab7185389efcdd5dace4643e04", 12 | "ffef5350b6f8762cc6272b0255e968f50b6577ed", 13 | "7ffd1401f599c70364eda431d29363e037b2c92c", 14 | "a0f06ca3cdb1e6e7f603794ef1cd9f9867f85551", 15 | "4b271beec86978454072b632f382c6ccb3938a45", 16 | "f5227cbd32973ec90f48f2547e6fe16c80b92bd5", 17 | "5af4dc18899e8ac95904eaf2b4abf1a2ca5e1507", 18 | "832b4a8497de78248f70c06e0f06e785a74fea4c", 19 | "0a1690e0640a212aafed1824eb208ffddab1789b", 20 | "fc80daf21bb484cfd42ad4ed4d17da48638199ea", 21 | "9f358a4addefcab294b83e4282bfef1f9625a249", 22 | "19f0805d8de36b6442e8c573074112ba72ad6780", 23 | "42fd8d7404f5127314e248b2cbbe1423f12faeb9", 24 | "fa59b93c6ce9db82ce57de9046eb738e9f3c0952", 25 | "802992c4220de19a90767f3000a79a31b98d0df7" 26 | ] 27 | -------------------------------------------------------------------------------- /test/fixtures/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ls . | awk -F '' 'NF == 40' | xargs rm 4 | rm testdata.tar.gz -f 5 | wget https://github.com/ipfs/go-ipld-git/raw/master/testdata.tar.gz 6 | tar xzf testdata.tar.gz 7 | rm testdata.tar.gz 8 | mv .git git 9 | 10 | find git/objects -type f | cut -d'/' -f3- | sed 's/\///g' | jq --raw-input . | jq --slurp . > objects.json 11 | paste <(find git/objects -type f) <(find git/objects -type f | cut -d'/' -f3- | sed 's/\///g') | xargs -L 1 mv -v 12 | rm -rf git 13 | -------------------------------------------------------------------------------- /test/mod.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict' 3 | 4 | const { expect } = require('aegir/utils/chai') 5 | const multicodec = require('multicodec') 6 | 7 | const mod = require('../src') 8 | 9 | describe('IPLD Format', () => { 10 | it('codec is git-raw', () => { 11 | expect(mod.codec).to.equal(multicodec.GIT_RAW) 12 | }) 13 | 14 | it('defaultHashAlg is sha1', () => { 15 | expect(mod.defaultHashAlg).to.equal(multicodec.SHA1) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/parse.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | /* eslint max-nested-callbacks: ["error", 8] */ 3 | 4 | 'use strict' 5 | 6 | const { expect } = require('aegir/utils/chai') 7 | const { Buffer } = require('buffer') 8 | const loadFixture = require('aegir/utils/fixtures') 9 | const zlib = require('zlib') 10 | const ipldGit = require('../src') 11 | const util = require('../src/util/util') 12 | 13 | const testObjectsJSON = require('./fixtures/objects.json') 14 | 15 | describe('utils', () => { 16 | describe('person line parsing', () => { 17 | it('parses generic line', (done) => { 18 | const info = util.parsePersonLine('Someone 123456 +0123') 19 | expect(info).to.exist() 20 | expect(info.name).to.equal('Someone') 21 | expect(info.email).to.equal('some@one.somewhere') 22 | expect(info.date).to.equal('1970-01-02T11:40:36+01:23') 23 | done() 24 | }) 25 | 26 | it('parses 3 segment name', (done) => { 27 | const info = util.parsePersonLine('So Me One 123456 +0123') 28 | expect(info).to.exist() 29 | expect(info.name).to.equal('So Me One') 30 | expect(info.email).to.equal('some@one.somewhere') 31 | expect(info.date).to.equal('1970-01-02T11:40:36+01:23') 32 | done() 33 | }) 34 | 35 | it('parses no name line', (done) => { 36 | const info = util.parsePersonLine(' 123456 +0123') 37 | expect(info).to.exist() 38 | expect(info.name).to.not.exist() 39 | expect(info.email).to.equal('some@one.somewhere') 40 | expect(info.date).to.equal('1970-01-02T11:40:36+01:23') 41 | done() 42 | }) 43 | 44 | it('parses no name line with space in front', (done) => { 45 | const info = util.parsePersonLine(' 123456 +0123') 46 | expect(info).to.exist() 47 | expect(info.name).to.not.exist() 48 | expect(info.email).to.equal('some@one.somewhere') 49 | expect(info.date).to.equal('1970-01-02T11:40:36+01:23') 50 | done() 51 | }) 52 | 53 | it('parses line with nonstandard info', (done) => { 54 | const info = util.parsePersonLine('Some One & Other One 987654 +4321') 55 | expect(info).to.exist() 56 | expect(info.name).to.equal('Some One & Other One') 57 | expect(info.email).to.equal('some@one.somewhere, other@one.elsewhere') 58 | expect(info.date).to.equal('1970-01-14T05:41:54+43:21') 59 | done() 60 | }) 61 | 62 | it('parses line without date info', (done) => { 63 | const info = util.parsePersonLine('Someone ') 64 | expect(info).to.exist() 65 | expect(info.name).to.equal('Someone') 66 | expect(info.email).to.equal('some.one@some.where') 67 | expect(info.date).to.not.exist() 68 | done() 69 | }) 70 | }) 71 | }) 72 | 73 | describe('git object parsing', () => { 74 | const objects = testObjectsJSON.map( 75 | (o) => [o, zlib.inflateSync(loadFixture('test/fixtures/' + o))] 76 | ) 77 | 78 | it('is parsing and serializing properly', async () => { 79 | for (const object of objects) { 80 | const expCid = util.shaToCid(Buffer.from(object[0], 'hex')) 81 | 82 | const cid = await ipldGit.util.cid(object[1]) 83 | expect(cid.equals(expCid)).to.be.true() 84 | } 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /test/resolver.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint max-nested-callbacks: ["error", 8] */ 2 | /* eslint-env mocha */ 3 | 'use strict' 4 | 5 | const { expect } = require('aegir/utils/chai') 6 | const { Buffer } = require('buffer') 7 | 8 | const CID = require('cids') 9 | 10 | const ipldGit = require('../src') 11 | const resolver = ipldGit.resolver 12 | 13 | describe('IPLD format resolver (local)', () => { 14 | let commitBlob 15 | let tagBlob 16 | let treeBlob 17 | let blobBlob 18 | 19 | before((done) => { 20 | const commitNode = { 21 | gitType: 'commit', 22 | tree: new CID('z8mWaJ1dZ9fH5EetPuRsj8jj26pXsgpsr'), 23 | parents: [ 24 | new CID('z8mWaFY1zpiZSXTBrz8i6A3o9vNvAs2CH') 25 | ], 26 | author: { 27 | name: 'John Doe', 28 | email: 'johndoe@example.com', 29 | date: '2017-06-12T23:22:12+02:00' 30 | }, 31 | committer: { 32 | name: 'John Doe', 33 | email: 'johndoe@example.com', 34 | date: '2017-06-12T23:22:12+02:00' 35 | }, 36 | encoding: 'ISO-8859-1', 37 | message: 'Encoded\n' 38 | } 39 | 40 | const tagNode = { 41 | gitType: 'tag', 42 | object: new CID('z8mWaHQaEAKd5KMRNU3npB3saSZmhFh3e'), 43 | type: 'commit', 44 | tag: 'v0.0.0', 45 | tagger: { 46 | name: 'John Doe', 47 | email: 'johndoe@example.com', 48 | date: '2017-06-12T23:22:12+02:00' 49 | }, 50 | message: 'A message\n' 51 | } 52 | 53 | const treeNode = { 54 | somefile: { 55 | hash: new CID('z8mWaJNVTadD7oum3m7f1dmarHvYhFV5b'), 56 | mode: '100644' 57 | }, 58 | somedir: { 59 | hash: new CID('z8mWaFY1zpiZSXTBrz8i6A3o9vNvAs2CH'), 60 | mode: '40000' 61 | } 62 | } 63 | treeNode['somedir.notactuallyadir'] = { 64 | hash: new CID('z8mWaJNVTadD7oum3m7f1dmarHvYhFV5b'), 65 | mode: '100644' 66 | } 67 | treeNode['somefile.notactuallyafile'] = { 68 | hash: new CID('z8mWaFY1zpiZSXTBrz8i6A3o9vNvAs2CH'), 69 | mode: '40000' 70 | } 71 | 72 | const blobNode = Buffer.from('626c6f62203800736f6d6564617461', 'hex') // blob 8\0somedata 73 | 74 | commitBlob = ipldGit.util.serialize(commitNode) 75 | tagBlob = ipldGit.util.serialize(tagNode) 76 | treeBlob = ipldGit.util.serialize(treeNode) 77 | blobBlob = ipldGit.util.serialize(blobNode) 78 | done() 79 | }) 80 | 81 | describe('commit', () => { 82 | it('resolver.tree', () => { 83 | const tree = resolver.tree(commitBlob) 84 | const paths = [...tree] 85 | 86 | expect(paths).to.have.members([ 87 | 'message', 88 | 'tree', 89 | 'author', 90 | 'author/name', 91 | 'author/email', 92 | 'author/date', 93 | 'committer', 94 | 'committer/name', 95 | 'committer/email', 96 | 'committer/date', 97 | 'parents', 98 | 'parents/0', 99 | 'encoding' 100 | ]) 101 | }) 102 | 103 | describe('resolver.resolve', () => { 104 | it('path within scope', () => { 105 | const result = resolver.resolve(commitBlob, 'message') 106 | expect(result.value).to.equal('Encoded\n') 107 | }) 108 | 109 | it('path within scope, but nested', () => { 110 | const result = resolver.resolve(commitBlob, 'author/name') 111 | expect(result.value).to.equal('John Doe') 112 | }) 113 | 114 | it('path out of scope', () => { 115 | const result = resolver.resolve(commitBlob, 'tree/foo/hash/bar/mode') 116 | expect(result.value.equals( 117 | new CID('z8mWaJ1dZ9fH5EetPuRsj8jj26pXsgpsr')) 118 | ).to.be.true() 119 | expect(result.remainderPath).to.equal('foo/hash/bar/mode') 120 | }) 121 | }) 122 | }) 123 | 124 | describe('tag', () => { 125 | it('resolver.tree', () => { 126 | const tree = resolver.tree(tagBlob) 127 | const paths = [...tree] 128 | 129 | expect(paths).to.have.members([ 130 | 'object', 131 | 'type', 132 | 'tag', 133 | 'message', 134 | 'tagger', 135 | 'tagger/name', 136 | 'tagger/email', 137 | 'tagger/date' 138 | ]) 139 | }) 140 | 141 | describe('resolver.resolve', () => { 142 | it('path within scope', () => { 143 | const result = resolver.resolve(tagBlob, 'message') 144 | expect(result.value).to.equal('A message\n') 145 | }) 146 | 147 | it('path within scope, but nested', () => { 148 | const result = resolver.resolve(tagBlob, 'tagger/name') 149 | expect(result.value).to.equal('John Doe') 150 | }) 151 | 152 | it('path out of scope', () => { 153 | const result = resolver.resolve(tagBlob, 'object/tree/foo/mode') 154 | expect(result.value.equals( 155 | new CID('z8mWaHQaEAKd5KMRNU3npB3saSZmhFh3e') 156 | )).to.be.true() 157 | expect(result.remainderPath).to.equal('tree/foo/mode') 158 | }) 159 | }) 160 | }) 161 | 162 | describe('tree', () => { 163 | it('resolver.tree', () => { 164 | const tree = resolver.tree(treeBlob) 165 | const paths = [...tree] 166 | 167 | expect(paths).to.have.members([ 168 | 'somedir.notactuallyadir', 169 | 'somedir.notactuallyadir/hash', 170 | 'somedir.notactuallyadir/mode', 171 | 'somedir', 172 | 'somedir/hash', 173 | 'somedir/mode', 174 | 'somefile', 175 | 'somefile/hash', 176 | 'somefile/mode', 177 | 'somefile.notactuallyafile', 178 | 'somefile.notactuallyafile/hash', 179 | 'somefile.notactuallyafile/mode' 180 | ]) 181 | }) 182 | 183 | describe('resolver.resolve', () => { 184 | it('path within scope, nested', () => { 185 | const result = resolver.resolve(treeBlob, 'somedir/mode') 186 | expect(result.value).to.equal('40000') 187 | }) 188 | 189 | it('path out of scope', () => { 190 | const result = resolver.resolve(treeBlob, 'somedir/hash/subfile/mode') 191 | expect(result.value.equals( 192 | new CID('z8mWaFY1zpiZSXTBrz8i6A3o9vNvAs2CH') 193 | )).to.be.true() 194 | expect(result.remainderPath).to.equal('subfile/mode') 195 | }) 196 | }) 197 | }) 198 | 199 | describe('blob', () => { 200 | it('resolver.tree', () => { 201 | const paths = resolver.tree(blobBlob).next() 202 | expect(paths.value).to.be.undefined() 203 | expect(paths.done).to.be.true() 204 | }) 205 | }) 206 | }) 207 | -------------------------------------------------------------------------------- /test/util.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict' 3 | 4 | const { expect } = require('aegir/utils/chai') 5 | const ipldGit = require('../src') 6 | const multicodec = require('multicodec') 7 | const multihash = require('multihashing-async').multihash 8 | const CID = require('cids') 9 | const { Buffer } = require('buffer') 10 | const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') 11 | 12 | describe('IPLD format util', () => { 13 | const tagNode = { 14 | gitType: 'tag', 15 | object: new CID('baf4bcfe5cqe5giojiciib5mci7gbb53xcxqot2i'), 16 | type: 'commit', 17 | tag: 'v0.0.0', 18 | tagger: { 19 | name: 'John Doe', 20 | email: 'johndoe@example.com', 21 | date: '2017-06-12T23:22:12+02:00' 22 | }, 23 | message: 'A message\n' 24 | } 25 | const tagBlob = ipldGit.util.serialize(tagNode) 26 | 27 | it('.serialize from Uint8Array', () => { 28 | const node = uint8ArrayFromString('blob-blob') 29 | const blob = ipldGit.util.serialize(node) 30 | 31 | expect(blob).to.deep.equal(node) 32 | }) 33 | 34 | it('.serialize from tree', () => { 35 | const node = { 36 | 'file.txt': { 37 | hash: new CID('baf4bcfe5cqe5giojiciib5mci7gbb53xcxqot2i'), 38 | mode: '644' 39 | } 40 | } 41 | const blob = ipldGit.util.serialize(node) 42 | const deserialized = ipldGit.util.deserialize(blob) 43 | 44 | expect(deserialized).to.deep.equal(node) 45 | }) 46 | 47 | it('.serialize and .deserialize', () => { 48 | expect(Buffer.isBuffer(tagBlob)).to.be.true() 49 | const deserialized = ipldGit.util.deserialize(tagBlob) 50 | 51 | // The `gitType` is not enumerable, hence `eql()` would find it. Thus 52 | // remove that property so that that check passes 53 | const expected = Object.assign({}, tagNode) 54 | delete expected.gitType 55 | expect(deserialized).to.eql(expected) 56 | }) 57 | 58 | it('.serialize and .deserialize Uint8Array', () => { 59 | expect(Buffer.isBuffer(Uint8Array.of(...tagBlob))).to.be.false() 60 | const deserialized = ipldGit.util.deserialize(Uint8Array.of(...tagBlob)) 61 | 62 | // The `gitType` is not enumerable, hence `eql()` would find it. Thus 63 | // remove that property so that that check passes 64 | const expected = Object.assign({}, tagNode) 65 | delete expected.gitType 66 | expect(deserialized).to.eql(expected) 67 | }) 68 | 69 | it('.cid', async () => { 70 | const cid = await ipldGit.util.cid(tagBlob) 71 | expect(cid.version).to.equal(1) 72 | expect(cid.codec).to.equal('git-raw') 73 | expect(cid.multihash).to.exist() 74 | const mh = multihash.decode(cid.multihash) 75 | expect(mh.name).to.equal('sha1') 76 | }) 77 | 78 | it('.cid with options', async () => { 79 | const cid = await ipldGit.util.cid(tagBlob, { 80 | hashAlg: multicodec.SHA3_512 81 | }) 82 | expect(cid.version).to.equal(1) 83 | expect(cid.codec).to.equal('git-raw') 84 | expect(cid.multihash).to.exist() 85 | const mh = multihash.decode(cid.multihash) 86 | expect(mh.name).to.equal('sha3-512') 87 | }) 88 | 89 | it('.cid errors unknown hashAlg', async () => { 90 | await expect(ipldGit.util.cid(tagNode, { hashAlg: 0xffffff } 91 | )).to.be.rejectedWith('Unrecognized function code: 16777215') 92 | }) 93 | }) 94 | --------------------------------------------------------------------------------