-
Notifications
You must be signed in to change notification settings - Fork 57
feat: draft for #33 that incorporates feedback #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a04a8f6
pkg: drop period
mikeal fd0ce17
invalidate cache
Gozala edbc56c
fix: vendor varint for pure ESM
mikeal b7aa2a6
fix: pass encode offset
Gozala 70cd8ce
fix: remove unecessary ImplicitSha256Digest
Gozala 66682df
chore: add links, tree and get APIs to Block
Gozala 04030cb
fix: typo in template literal
Gozala File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| // @ts-check | ||
|
|
||
| /** | ||
| * @typedef {import('./interface').BaseEncoder} BaseEncoder | ||
| * @typedef {import('./interface').BaseDecoder} BaseDecoder | ||
| * @typedef {import('./interface').BaseCodec} BaseCodec | ||
| */ | ||
|
|
||
| /** | ||
| * @template T | ||
| * @typedef {import('./interface').Multibase<T>} Multibase | ||
| */ | ||
| /** | ||
| * @template T | ||
| * @typedef {import('./interface').MultibaseEncoder<T>} MultibaseEncoder | ||
| */ | ||
|
|
||
| /** | ||
| * Class represents both BaseEncoder and MultibaseEncoder meaning it | ||
| * can be used to encode to multibase or base encode without multibase | ||
| * prefix. | ||
| * @class | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @implements {MultibaseEncoder<Prefix>} | ||
| * @implements {BaseEncoder} | ||
| */ | ||
| class Encoder { | ||
| /** | ||
| * @param {Base} name | ||
| * @param {Prefix} prefix | ||
| * @param {(bytes:Uint8Array) => string} baseEncode | ||
| */ | ||
| constructor (name, prefix, baseEncode) { | ||
| this.name = name | ||
| this.prefix = prefix | ||
| this.baseEncode = baseEncode | ||
| } | ||
|
|
||
| /** | ||
| * @param {Uint8Array} bytes | ||
| * @returns {Multibase<Prefix>} | ||
| */ | ||
| encode (bytes) { | ||
| // @ts-ignore | ||
| return `${this.prefix}${this.baseEncode(bytes)}` | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @template T | ||
| * @typedef {import('./interface').MultibaseDecoder<T>} MultibaseDecoder | ||
| */ | ||
|
|
||
| /** | ||
| * Class represents both BaseDecoder and MultibaseDecoder so it could be used | ||
| * to decode multibases (with matching prefix) or just base decode strings | ||
| * with corresponding base encoding. | ||
| * @class | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @implements {MultibaseDecoder<Prefix>} | ||
| * @implements {BaseDecoder} | ||
| */ | ||
| class Decoder { | ||
| /** | ||
| * @param {Base} name | ||
| * @param {Prefix} prefix | ||
| * @param {(text:string) => Uint8Array} baseDecode | ||
| */ | ||
| constructor (name, prefix, baseDecode) { | ||
| this.name = name | ||
| this.prefix = prefix | ||
| this.baseDecode = baseDecode | ||
| } | ||
|
|
||
| /** | ||
| * @param {string} text | ||
| */ | ||
| decode (text) { | ||
| switch (text[0]) { | ||
| case this.prefix: { | ||
| return this.baseDecode(text.slice(1)) | ||
| } | ||
| default: { | ||
| throw Error(`${this.name} expects input starting with ${this.prefix} and can not decode "${text}"`) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @template T | ||
| * @typedef {import('./interface').MultibaseCodec<T>} MultibaseCodec | ||
| */ | ||
|
|
||
| /** | ||
| * @class | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @implements {MultibaseCodec<Prefix>} | ||
| * @implements {MultibaseEncoder<Prefix>} | ||
| * @implements {MultibaseDecoder<Prefix>} | ||
| * @implements {BaseCodec} | ||
| * @implements {BaseEncoder} | ||
| * @implements {BaseDecoder} | ||
| */ | ||
| export class Codec { | ||
| /** | ||
| * @param {Base} name | ||
| * @param {Prefix} prefix | ||
| * @param {(bytes:Uint8Array) => string} baseEncode | ||
| * @param {(text:string) => Uint8Array} baseDecode | ||
| */ | ||
| constructor (name, prefix, baseEncode, baseDecode) { | ||
| this.name = name | ||
| this.prefix = prefix | ||
| this.baseEncode = baseEncode | ||
| this.baseDecode = baseDecode | ||
| this.encoder = new Encoder(name, prefix, baseEncode) | ||
| this.decoder = new Decoder(name, prefix, baseDecode) | ||
| } | ||
|
|
||
| /** | ||
| * @param {Uint8Array} input | ||
| */ | ||
| encode (input) { | ||
| return this.encoder.encode(input) | ||
| } | ||
|
|
||
| decode (input) { | ||
| return this.decoder.decode(input) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @param {Object} options | ||
| * @param {Base} options.name | ||
| * @param {Prefix} options.prefix | ||
| * @param {string} options.alphabet | ||
| * @param {(input:Uint8Array, alphabet:string) => string} options.encode | ||
| * @param {(input:string, alphabet:string) => Uint8Array} options.decode | ||
| */ | ||
| export const withAlphabet = ({ name, prefix, encode, decode, alphabet }) => | ||
| from({ | ||
| name, | ||
| prefix, | ||
| encode: input => encode(input, alphabet), | ||
| decode: input => { | ||
| for (const char of input) { | ||
| if (alphabet.indexOf(char) < 0) { | ||
| throw new Error(`invalid ${name} character`) | ||
| } | ||
| } | ||
| return decode(input, alphabet) | ||
| } | ||
| }) | ||
|
|
||
| /** | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @template Settings | ||
| * | ||
| * @param {Object} options | ||
| * @param {Base} options.name | ||
| * @param {Prefix} options.prefix | ||
| * @param {Settings} options.settings | ||
| * @param {(input:Uint8Array, settings:Settings) => string} options.encode | ||
| * @param {(input:string, settings:Settings) => Uint8Array} options.decode | ||
| */ | ||
|
|
||
| export const withSettings = ({ name, prefix, settings, encode, decode }) => | ||
| from({ | ||
| name, | ||
| prefix, | ||
| encode: (input) => encode(input, settings), | ||
| decode: (input) => decode(input, settings) | ||
| }) | ||
|
|
||
| /** | ||
| * @template {string} Base | ||
| * @template {string} Prefix | ||
| * @param {Object} options | ||
| * @param {Base} options.name | ||
| * @param {Prefix} options.prefix | ||
| * @param {(bytes:Uint8Array) => string} options.encode | ||
| * @param {(input:string) => Uint8Array} options.decode | ||
| * @returns {Codec<Base, Prefix>} | ||
| */ | ||
| export const from = ({ name, prefix, encode, decode }) => | ||
| new Codec(name, prefix, encode, decode) | ||
|
|
||
| export const notImplemented = ({ name, prefix }) => | ||
| from({ | ||
| name, | ||
| prefix, | ||
| encode: _ => { | ||
| throw Error(`No ${name} encoder implementation was provided`) | ||
| }, | ||
| decode: _ => { | ||
| throw Error(`No ${name} decoder implemnetation was provided`) | ||
| } | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,12 @@ | ||
| import { fromHex, toHex } from '../bytes.js' | ||
| // @ts-check | ||
|
|
||
| const create = function base16 (alphabet) { | ||
| return { | ||
| encode: input => toHex(input), | ||
| decode (input) { | ||
| for (const char of input) { | ||
| if (alphabet.indexOf(char) < 0) { | ||
| throw new Error('invalid base16 character') | ||
| } | ||
| } | ||
| return fromHex(input) | ||
| } | ||
| } | ||
| } | ||
| import { fromHex, toHex } from '../bytes.js' | ||
| import { withAlphabet } from './base.js' | ||
|
|
||
| export default { prefix: 'f', name: 'base16', ...create('0123456789abcdef') } | ||
| export const base16 = withAlphabet({ | ||
| prefix: 'f', | ||
| name: 'base16', | ||
| alphabet: '0123456789abcdef', | ||
| encode: toHex, | ||
| decode: fromHex | ||
| }) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this mean exactly?
i think i’d prefer this to be
{ base32, base58btc }we actually need the default behavior of
toString()without a requested base encoding to be stable, so we shouldn’t have a way to set a different default base encoding here. so simply passing in the implementations should be sufficient.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments in the ./cid/interface.ts attempt to clarify that. Inlining here for convenience:
Well
basesupposed to represent base codec for whatever encoding you choose to use for the CID been created. If you make itbase32that would mean CIDs could only be inbase32encoding. In fact if anythingbase58btcis kind of outlier here, which only there to supporttoV0and I kind of wish passing it was unnecessary.Are you saying user should not be able to create CID with a different base encoding ? Or simply that decision about encoding should be deferred until
toString()is called and it should default tobase32if no encodnig is passed ?If later, I understand your argument. However this config is also used for parsing CID in string representations so that when you do following:
Would you expect
c1.toString()to printbafybeibrypkxbagyiy5dyy5ssi67lioubll2opvolikk6wcccps7kbfmgminstead ?If you expect to print in
base32then{ base32, base58btc }as CID config makes sense. If you expect it to print in base64 than I'd say current config makes more sense.