diff --git a/.gitignore b/.gitignore index 3a1eff8c..98fb3364 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /pkg/*/lib/ /pkg/*/README.md.ts /pkg/*/test-fixture/tsconfig.json +/pkg/*/tests/tsconfig.json /pkg/*/tsconfig.json /pnpm-debug.log /pnpm-lock.yaml diff --git a/mk/make-pkg-tsconfig.mjs b/mk/make-pkg-tsconfig.mjs index 7898a6b7..e95f5895 100644 --- a/mk/make-pkg-tsconfig.mjs +++ b/mk/make-pkg-tsconfig.mjs @@ -45,7 +45,8 @@ for (const filename of ["src/mod.ts", "src/main.ts"]) { await fs.writeFile("tsconfig.json", JSON.stringify(tsconfig, undefined, 2)); -const tsconfigTestFixture = { +/** @type {typeof tsconfig} */ +const tsconfigTest = { extends: "../../../mk/tsconfig-base.json", compilerOptions: { rootDir: "..", @@ -55,10 +56,12 @@ const tsconfigTestFixture = { ], }; -let hasTestFixture = false; -try { - hasTestFixture = (await fs.stat("test-fixture")).isDirectory(); -} catch {} -if (hasTestFixture) { - await fs.writeFile("test-fixture/tsconfig.json", JSON.stringify(tsconfigTestFixture, undefined, 2)); +for (const dir of ["test-fixture", "tests"]) { + let found = false; + try { + found = (await fs.stat(dir)).isDirectory(); + } catch {} + if (found) { + await fs.writeFile(path.join(dir, "tsconfig.json"), JSON.stringify(tsconfigTest, undefined, 2)); + } } diff --git a/pkg/keychain/test-fixture/key-store.ts b/pkg/keychain/test-fixture/key-store.ts index b92d61fa..28d0213d 100644 --- a/pkg/keychain/test-fixture/key-store.ts +++ b/pkg/keychain/test-fixture/key-store.ts @@ -50,7 +50,7 @@ export async function execute(keyChain: KeyChain, enabled: Enable = {}): Promise const keys1 = gen.map(([pvt]) => pvt.name).map(String); const keyNames2 = await keyChain.listKeys(); - keyNames2.sort((a, b) => a.compare(b)); + keyNames2.sort(Name.compare); const keys2 = (await Promise.all(keyNames2.map((n) => keyChain.getKey(n, "signer")))) .map((pvt) => pvt.name.toString()); @@ -59,7 +59,7 @@ export async function execute(keyChain: KeyChain, enabled: Enable = {}): Promise .map((u) => keyChain.deleteKey(new Name(u))), ); const keyNames3 = await keyChain.listKeys(); - keyNames3.sort((a, b) => a.compare(b)); + keyNames3.sort(Name.compare); const keys3 = (await Promise.all(keyNames3.map((n) => keyChain.getKey(n, "verifier")))) .map((pub) => pub.name.toString()); diff --git a/pkg/packet/src/name/component.ts b/pkg/packet/src/name/component.ts index f786c704..b1999d54 100644 --- a/pkg/packet/src/name/component.ts +++ b/pkg/packet/src/name/component.ts @@ -178,9 +178,7 @@ export class Component { /** Compare this component with other. */ public compare(other: ComponentLike): Component.CompareResult { - other = Component.from(other); - return 2 * Math.sign(this.type - other.type || this.length - other.length || - bufferCompare(this.value, other.value)); + return Component.compare(this, Component.from(other)); } /** Determine if this component equals other. */ @@ -199,4 +197,10 @@ export namespace Component { /** lhs is greater than rhs */ GT = 2, } + + /** Compare two components. */ + export function compare(lhs: Component, rhs: Component): CompareResult { + return 2 * Math.sign(lhs.type - rhs.type || lhs.length - rhs.length || + bufferCompare(lhs.value, rhs.value)); + } } diff --git a/pkg/packet/src/name/name.ts b/pkg/packet/src/name/name.ts index 889dab8b..f3a21ab4 100644 --- a/pkg/packet/src/name/name.ts +++ b/pkg/packet/src/name/name.ts @@ -147,8 +147,8 @@ export class Name { public append(...args: unknown[]) { let suffix: readonly ComponentLike[]; if (args.length === 2 && - typeof (args[0] as NamingConvention).create === "function") { - suffix = [(args[0] as NamingConvention).create(args[1])]; + typeof (args[0] as NamingConvention).create === "function") { + suffix = [(args[0] as NamingConvention).create(args[1])]; } else { suffix = args as readonly ComponentLike[]; } @@ -157,27 +157,12 @@ export class Name { /** Return a copy of Name with i-th component replaced with `comp`. */ public replaceAt(i: number, comp: ComponentLike): Name { - const comps: ComponentLike[] = [...this.comps]; - comps.splice(i, 1, comp); - return new Name(comps); + return new Name((this.comps as readonly ComponentLike[]).toSpliced(i, 1, comp)); } /** Compare with other name. */ public compare(other: NameLike): Name.CompareResult { - other = Name.from(other); - const commonSize = Math.min(this.length, other.length); - const cmp = this.comparePrefix(other, commonSize); - if (cmp !== Name.CompareResult.EQUAL) { - return cmp; - } - - if (this.length > commonSize) { - return Name.CompareResult.RPREFIX; - } - if (other.length > commonSize) { - return Name.CompareResult.LPREFIX; - } - return Name.CompareResult.EQUAL; + return Name.compare(this, Name.from(other)); } /** Determine if this name equals other. */ @@ -186,23 +171,16 @@ export class Name { if (this.hex_ !== undefined && other.hex_ !== undefined) { return this.hex_ === other.hex_; } - return this.length === other.length && this.comparePrefix(other, this.length) === Name.CompareResult.EQUAL; + return this.length === other.length && comparePrefix(this, other, this.length) === Name.CompareResult.EQUAL; } /** Determine if this name is a prefix of other. */ public isPrefixOf(other: NameLike): boolean { other = Name.from(other); - return this.length <= other.length && this.comparePrefix(other, this.length) === Name.CompareResult.EQUAL; - } - - private comparePrefix(other: Name, n: number): Name.CompareResult { - for (let i = 0; i < n; ++i) { - const cmp = this.comps[i]!.compare(other.comps[i]!); - if (cmp !== Component.CompareResult.EQUAL) { - return cmp as unknown as Name.CompareResult; - } + if (this.hex_ !== undefined && other.hex_ !== undefined) { + return other.hex_.startsWith(this.hex_); } - return Name.CompareResult.EQUAL; + return this.length <= other.length && comparePrefix(this, other, this.length) === Name.CompareResult.EQUAL; } public encodeTo(encoder: Encoder) { @@ -233,4 +211,32 @@ export namespace Name { /** rhs is less than, but not a prefix of lhs */ GT = 2, } + + /** Compare two names. */ + export function compare(lhs: Name, rhs: Name): CompareResult { + const commonSize = Math.min(lhs.length, rhs.length); + const cmp = comparePrefix(lhs, rhs, commonSize); + if (cmp !== CompareResult.EQUAL) { + return cmp; + } + + if (lhs.length > commonSize) { + return CompareResult.RPREFIX; + } + if (rhs.length > commonSize) { + return CompareResult.LPREFIX; + } + return CompareResult.EQUAL; + } +} + +/** Compare first n components between two names. */ +function comparePrefix(lhs: Name, rhs: Name, n: number): Name.CompareResult { + for (let i = 0; i < n; ++i) { + const cmp = lhs.comps[i]!.compare(rhs.comps[i]!); + if (cmp !== Component.CompareResult.EQUAL) { + return cmp as unknown as Name.CompareResult; + } + } + return Name.CompareResult.EQUAL; } diff --git a/pkg/trust-schema/tests/schema/pattern.t.ts b/pkg/trust-schema/tests/schema/pattern.t.ts index ff2ed0bd..ed8c16b6 100644 --- a/pkg/trust-schema/tests/schema/pattern.t.ts +++ b/pkg/trust-schema/tests/schema/pattern.t.ts @@ -10,9 +10,7 @@ function match(p: P.Pattern, name: NameLike): P.Vars[] { } function build(p: P.Pattern, vars: P.VarsLike): Name[] { - const list = Array.from(p.build(vars)); - list.sort((a, b) => a.compare(b)); - return list; + return Array.from(p.build(vars)).toSorted(Name.compare); } test("const variable concat", () => {