@amritk/helpers
Advanced tools
| /** | ||
| * Escapes a JSON Schema `pattern` so it can be embedded between the slashes of | ||
| * a generated regex literal (`/…/`). | ||
| * | ||
| * A `pattern` is an ECMA-262 regex *body*, and the generated text goes into a | ||
| * regex literal — not a string literal — so backslashes are regex syntax and | ||
| * must be left exactly as-is (doubling `\d` to `\\d` would change it from "a | ||
| * digit" to "a literal backslash followed by d"). The only character that would | ||
| * corrupt the surrounding literal is an *unescaped* `/`, which would close it | ||
| * early. So we escape bare slashes to `\/` while leaving every existing escape | ||
| * sequence (including an already-escaped `\/`) untouched. | ||
| * | ||
| * @example | ||
| * escapeRegexPattern('\\d{4}/\\d{2}') // → '\\d{4}\\/\\d{2}' (i.e. \d{4}\/\d{2}) | ||
| */ | ||
| export declare const escapeRegexPattern: (pattern: string) => string; | ||
| //# sourceMappingURL=escape-regex-pattern.d.ts.map |
| {"version":3,"file":"escape-regex-pattern.d.ts","sourceRoot":"","sources":["../src/escape-regex-pattern.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,YAAa,MAAM,KAAG,MAIwB,CAAA"} |
| /** | ||
| * Escapes a JSON Schema `pattern` so it can be embedded between the slashes of | ||
| * a generated regex literal (`/…/`). | ||
| * | ||
| * A `pattern` is an ECMA-262 regex *body*, and the generated text goes into a | ||
| * regex literal — not a string literal — so backslashes are regex syntax and | ||
| * must be left exactly as-is (doubling `\d` to `\\d` would change it from "a | ||
| * digit" to "a literal backslash followed by d"). The only character that would | ||
| * corrupt the surrounding literal is an *unescaped* `/`, which would close it | ||
| * early. So we escape bare slashes to `\/` while leaving every existing escape | ||
| * sequence (including an already-escaped `\/`) untouched. | ||
| * | ||
| * @example | ||
| * escapeRegexPattern('\\d{4}/\\d{2}') // → '\\d{4}\\/\\d{2}' (i.e. \d{4}\/\d{2}) | ||
| */ | ||
| export const escapeRegexPattern = (pattern) => | ||
| // Match either an escape sequence (`\` + any char, kept verbatim) or a bare | ||
| // `/` (escaped). Consuming escape pairs first means the slash in `\/` is never | ||
| // seen as bare, so it is not double-escaped. | ||
| pattern.replace(/\\[\s\S]|\//g, (match) => (match === '/' ? '\\/' : match)); |
| import { describe, expect, it } from 'vitest' | ||
| import { escapeRegexPattern } from './escape-regex-pattern' | ||
| describe('escape-regex-pattern', () => { | ||
| it('escapes bare forward slashes so the regex literal does not close early', () => { | ||
| expect(escapeRegexPattern('a/b')).toBe('a\\/b') | ||
| // Input \d{4}/\d{2}/\d{2} → \d{4}\/\d{2}\/\d{2} | ||
| expect(escapeRegexPattern('\\d{4}/\\d{2}/\\d{2}')).toBe('\\d{4}\\/\\d{2}\\/\\d{2}') | ||
| }) | ||
| it('leaves backslash escape sequences exactly as-is (does not double them)', () => { | ||
| // \d must stay \d — doubling it would match a literal backslash, not a digit. | ||
| expect(escapeRegexPattern('\\d+')).toBe('\\d+') | ||
| expect(escapeRegexPattern('\\w\\s')).toBe('\\w\\s') | ||
| }) | ||
| it('does not double-escape an already-escaped slash', () => { | ||
| // \/ (escaped slash) stays \/, not \\\/. | ||
| expect(escapeRegexPattern('\\/')).toBe('\\/') | ||
| }) | ||
| it('leaves regex metacharacters that do not affect the literal untouched', () => { | ||
| expect(escapeRegexPattern('^[a-z]+$')).toBe('^[a-z]+$') | ||
| }) | ||
| it('round-trips: the escaped body parses to a regex equivalent to the source pattern', () => { | ||
| for (const pattern of ['\\d{4}/\\d{2}', 'a/b/c', '^https?:\\/\\/', '\\w+@\\w+']) { | ||
| // Build the literal the generator emits and read its source back out. | ||
| const re = new RegExp(escapeRegexPattern(pattern)) | ||
| // The RegExp's own source, with \/ normalized back to /, equals the input. | ||
| expect(re.source.replace(/\\\//g, '/')).toBe(pattern.replace(/\\\//g, '/')) | ||
| } | ||
| }) | ||
| }) |
| /** | ||
| * Escapes a JSON Schema `pattern` so it can be embedded between the slashes of | ||
| * a generated regex literal (`/…/`). | ||
| * | ||
| * A `pattern` is an ECMA-262 regex *body*, and the generated text goes into a | ||
| * regex literal — not a string literal — so backslashes are regex syntax and | ||
| * must be left exactly as-is (doubling `\d` to `\\d` would change it from "a | ||
| * digit" to "a literal backslash followed by d"). The only character that would | ||
| * corrupt the surrounding literal is an *unescaped* `/`, which would close it | ||
| * early. So we escape bare slashes to `\/` while leaving every existing escape | ||
| * sequence (including an already-escaped `\/`) untouched. | ||
| * | ||
| * @example | ||
| * escapeRegexPattern('\\d{4}/\\d{2}') // → '\\d{4}\\/\\d{2}' (i.e. \d{4}\/\d{2}) | ||
| */ | ||
| export const escapeRegexPattern = (pattern: string): string => | ||
| // Match either an escape sequence (`\` + any char, kept verbatim) or a bare | ||
| // `/` (escaped). Consuming escape pairs first means the slash in `\/` is never | ||
| // seen as bare, so it is not double-escaped. | ||
| pattern.replace(/\\[\s\S]|\//g, (match) => (match === '/' ? '\\/' : match)) |
@@ -9,7 +9,8 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12'; | ||
| * | ||
| * Only the direct properties and their nested schemas are walked — this does not need | ||
| * to be infinitely deep because the build system generates separate files for each $def, | ||
| * so each schema is relatively shallow. | ||
| * Walks both object properties and array elements, so a `$dynamicRef` nested | ||
| * inside a keyword whose value is an array of subschemas (`allOf`, `anyOf`, | ||
| * `oneOf`, `prefixItems`, …) is rewritten too. The build system generates a | ||
| * separate file per `$def`, so each schema walked here is relatively shallow. | ||
| */ | ||
| export declare const resolveDynamicRefs: (schema: JSONSchema, dynamicRefMap: Record<string, string>) => JSONSchema; | ||
| //# sourceMappingURL=resolve-dynamic-refs.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"resolve-dynamic-refs.d.ts","sourceRoot":"","sources":["../src/resolve-dynamic-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,WAAY,UAAU,iBAAiB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,UAkC9F,CAAA"} | ||
| {"version":3,"file":"resolve-dynamic-refs.d.ts","sourceRoot":"","sources":["../src/resolve-dynamic-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,WAAY,UAAU,iBAAiB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,UAuC9F,CAAA"} |
@@ -8,5 +8,6 @@ /** | ||
| * | ||
| * Only the direct properties and their nested schemas are walked — this does not need | ||
| * to be infinitely deep because the build system generates separate files for each $def, | ||
| * so each schema is relatively shallow. | ||
| * Walks both object properties and array elements, so a `$dynamicRef` nested | ||
| * inside a keyword whose value is an array of subschemas (`allOf`, `anyOf`, | ||
| * `oneOf`, `prefixItems`, …) is rewritten too. The build system generates a | ||
| * separate file per `$def`, so each schema walked here is relatively shallow. | ||
| */ | ||
@@ -23,5 +24,10 @@ export const resolveDynamicRefs = (schema, dynamicRefMap) => { | ||
| const walk = (obj) => { | ||
| if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { | ||
| if (typeof obj !== 'object' || obj === null) { | ||
| return; | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| for (const item of obj) | ||
| walk(item); | ||
| return; | ||
| } | ||
| const record = obj; | ||
@@ -28,0 +34,0 @@ if ('$dynamicRef' in record && typeof record['$dynamicRef'] === 'string') { |
@@ -111,3 +111,11 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12'; | ||
| }; | ||
| /** Type guard to check if schema has dependentRequired (2020-12). */ | ||
| export declare const hasDependentRequired: (schema: JSONSchema) => schema is SchemaObject & { | ||
| dependentRequired: Record<string, readonly string[]>; | ||
| }; | ||
| /** Type guard to check if schema has a propertyNames subschema. */ | ||
| export declare const hasPropertyNames: (schema: JSONSchema) => schema is SchemaObject & { | ||
| propertyNames: JSONSchema; | ||
| }; | ||
| export { hasRef } from './has-ref.js'; | ||
| //# sourceMappingURL=schema-guards.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"schema-guards.d.ts","sourceRoot":"","sources":["../src/schema-guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE,KAAK,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,GAAG,OAAO,CAAC,CAAA;AAExD,iDAAiD;AACjD,eAAO,MAAM,cAAc,WAAY,UAAU,KAAG,MAAM,IAAI,YAE7D,CAAA;AAED,wDAAwD;AACxD,eAAO,MAAM,OAAO,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAEnF,CAAA;AAED,wDAAwD;AACxD,eAAO,MAAM,cAAc,WAAY,UAAU,KAAG,MAAM,IAAI,UAAU,CAAC,MAExE,CAAA;AAED,mDAAmD;AACnD,eAAO,MAAM,aAAa,WAChB,UAAU,KACjB,MAAM,IAAI,YAAY,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAOnE,CAAA;AAED,6CAA6C;AAC7C,eAAO,MAAM,OAAO,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;CAE/F,CAAA;AAED,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAEtF,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,UAAU,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAEzF,CAAA;AAED,+CAA+C;AAC/C,eAAO,MAAM,SAAS,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAEvF,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,UAAU,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAE1F,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,WAAW,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;CAEvG,CAAA;AAED,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;CAEpG,CAAA;AAED,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;CAEpG,CAAA;AAED,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;CAEpG,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,WAAW,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAEtG,CAAA;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,KAAK,EAAE,YAAY,CAAA;CAQ3F,CAAA;AAED,6DAA6D;AAC7D,eAAO,MAAM,uBAAuB,WAC1B,UAAU,KACjB,MAAM,IAAI,YAAY,GAAG;IAAE,oBAAoB,EAAE,UAAU,GAAG,OAAO,CAAA;CAEvE,CAAA;AAED,kDAAkD;AAClD,eAAO,MAAM,YAAY,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAE7F,CAAA;AAED,kDAAkD;AAClD,eAAO,MAAM,YAAY,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAE7F,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,UAAU,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAEzF,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,UAAU,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAEzF,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAE3G,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAE3G,CAAA;AAED,mDAAmD;AACnD,eAAO,MAAM,aAAa,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAE/F,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,WAAW,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAE3F,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,WAAW,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAE3F,CAAA;AAED,oDAAoD;AACpD,eAAO,MAAM,cAAc,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,WAAW,EAAE,OAAO,CAAA;CAElG,CAAA;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAErG,CAAA;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,WAAY,UAAU,KAAG,MAAM,IAAI,YAAY,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAErG,CAAA;AAED,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA"} | ||
| {"version":3,"file":"schema-guards.d.ts","sourceRoot":"","sources":["../src/schema-guards.ts"],"names":[],"mappings":"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"} |
@@ -120,2 +120,13 @@ /** Type guard to check if schema is not false */ | ||
| }; | ||
| /** Type guard to check if schema has dependentRequired (2020-12). */ | ||
| export const hasDependentRequired = (schema) => { | ||
| return (isSchemaObject(schema) && | ||
| 'dependentRequired' in schema && | ||
| typeof schema.dependentRequired === 'object' && | ||
| schema.dependentRequired !== null); | ||
| }; | ||
| /** Type guard to check if schema has a propertyNames subschema. */ | ||
| export const hasPropertyNames = (schema) => { | ||
| return isSchemaObject(schema) && 'propertyNames' in schema; | ||
| }; | ||
| export { hasRef } from './has-ref.js'; |
+1
-1
| { | ||
| "name": "@amritk/helpers", | ||
| "version": "0.7.1", | ||
| "version": "0.8.0", | ||
| "description": "Shared utilities for the mjst code generation ecosystem.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -70,2 +70,14 @@ import { describe, expect, it } from 'vitest' | ||
| it('replaces $dynamicRef nested inside an array keyword (allOf)', () => { | ||
| const schema = { | ||
| allOf: [{ $dynamicRef: '#meta' }, { type: 'object' as const, properties: { x: { $dynamicRef: '#meta' } } }], | ||
| } | ||
| const result = resolveDynamicRefs(schema, { '#meta': '#/$defs/schema' }) | ||
| expect(result).toEqual({ | ||
| allOf: [{ $ref: '#/$defs/schema' }, { type: 'object', properties: { x: { $ref: '#/$defs/schema' } } }], | ||
| }) | ||
| }) | ||
| it('handles nested $dynamicRef in property sub-schemas', () => { | ||
@@ -72,0 +84,0 @@ const schema = { |
@@ -10,5 +10,6 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12' | ||
| * | ||
| * Only the direct properties and their nested schemas are walked — this does not need | ||
| * to be infinitely deep because the build system generates separate files for each $def, | ||
| * so each schema is relatively shallow. | ||
| * Walks both object properties and array elements, so a `$dynamicRef` nested | ||
| * inside a keyword whose value is an array of subschemas (`allOf`, `anyOf`, | ||
| * `oneOf`, `prefixItems`, …) is rewritten too. The build system generates a | ||
| * separate file per `$def`, so each schema walked here is relatively shallow. | ||
| */ | ||
@@ -28,6 +29,11 @@ export const resolveDynamicRefs = (schema: JSONSchema, dynamicRefMap: Record<string, string>): JSONSchema => { | ||
| const walk = (obj: unknown): void => { | ||
| if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { | ||
| if (typeof obj !== 'object' || obj === null) { | ||
| return | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| for (const item of obj) walk(item) | ||
| return | ||
| } | ||
| const record = obj as Record<string, unknown> | ||
@@ -34,0 +40,0 @@ |
@@ -10,2 +10,3 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12' | ||
| hasDefault, | ||
| hasDependentRequired, | ||
| hasEnum, | ||
@@ -29,2 +30,3 @@ hasExamples, | ||
| hasProperties, | ||
| hasPropertyNames, | ||
| hasRef, | ||
@@ -391,2 +393,21 @@ hasRequired, | ||
| // hasDependentRequired | ||
| it('hasDependentRequired returns true for an object value', () => { | ||
| expect(hasDependentRequired({ dependentRequired: { a: ['b'] } })).toBe(true) | ||
| }) | ||
| it('hasDependentRequired returns false when missing or non-object', () => { | ||
| expect(hasDependentRequired({})).toBe(false) | ||
| expect(hasDependentRequired({ dependentRequired: null } as unknown as JSONSchema)).toBe(false) | ||
| }) | ||
| // hasPropertyNames | ||
| it('hasPropertyNames returns true when the keyword is present', () => { | ||
| expect(hasPropertyNames({ propertyNames: { pattern: '^[a-z]+$' } })).toBe(true) | ||
| }) | ||
| it('hasPropertyNames returns false when missing', () => { | ||
| expect(hasPropertyNames({})).toBe(false) | ||
| }) | ||
| // hasRef | ||
@@ -393,0 +414,0 @@ it('hasRef returns true when $ref is a string', () => { |
+17
-0
@@ -160,2 +160,19 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12' | ||
| /** Type guard to check if schema has dependentRequired (2020-12). */ | ||
| export const hasDependentRequired = ( | ||
| schema: JSONSchema, | ||
| ): schema is SchemaObject & { dependentRequired: Record<string, readonly string[]> } => { | ||
| return ( | ||
| isSchemaObject(schema) && | ||
| 'dependentRequired' in schema && | ||
| typeof schema.dependentRequired === 'object' && | ||
| schema.dependentRequired !== null | ||
| ) | ||
| } | ||
| /** Type guard to check if schema has a propertyNames subschema. */ | ||
| export const hasPropertyNames = (schema: JSONSchema): schema is SchemaObject & { propertyNames: JSONSchema } => { | ||
| return isSchemaObject(schema) && 'propertyNames' in schema | ||
| } | ||
| export { hasRef } from './has-ref' |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
293448
2.91%105
5%6751
2.38%