@narrative.io/jsonforms-provider-protocols 3.0.0-beta.19 → 3.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-eval-ajv.js","sources":["../src/no-eval-ajv.ts"],"sourcesContent":["import {\n Validator,\n type OutputUnit,\n type Schema,\n type SchemaDraft,\n} from \"@cfworker/json-schema\";\n\n/**\n * CSP-safe JSON Schema validation backed by `@cfworker/json-schema`.\n *\n * Cloudflare Pages and similar strict-CSP environments forbid `new Function`,\n * which is how AJV compiles validators. This factory returns an\n * AJV-shaped facade whose `compile()` produces a synchronous validator\n * function `(data) => boolean` with a mutable `errors` property — enough\n * for `<JsonForms :ajv=\"...\" />` to drop in without any other changes.\n *\n * Only `compile()` is functional; the rest of the surface (`addSchema`,\n * `getSchema`, `removeSchema`, `addFormat`, `addKeyword`, `opts`) exists\n * as no-ops for forward compatibility with plugins that probe the AJV\n * interface but never reach those methods at runtime.\n */\n\n// AJV's ErrorObject shape. We don't import `ajv` here to keep the lib's\n// zero-runtime-deps philosophy intact; the consumer's transitive AJV types\n// are structurally compatible.\nexport interface NoEvalErrorObject {\n instancePath: string;\n schemaPath: string;\n keyword: string;\n params: Record<string, unknown>;\n message?: string;\n}\n\nexport interface NoEvalValidateFunction {\n (data: unknown): boolean;\n errors: NoEvalErrorObject[] | null;\n}\n\n// Minimal subset of AJV's surface that JsonForms touches. The factory\n// returns this as `unknown as Ajv` at the call site; consumers cast on\n// import or pass directly to `<JsonForms :ajv=\"...\" />`.\nexport interface NoEvalAjv {\n compile: (schema: unknown) => NoEvalValidateFunction;\n addSchema: (schema: unknown, key?: string) => NoEvalAjv;\n getSchema: (key: string) => NoEvalValidateFunction | undefined;\n removeSchema: (schemaKeyRef?: unknown) => NoEvalAjv;\n addFormat: (name: string, format: unknown) => NoEvalAjv;\n addKeyword: (definition: unknown) => NoEvalAjv;\n opts: Readonly<Record<string, unknown>>;\n}\n\nexport interface CreateNoEvalAjvOptions {\n /**\n * JSON Schema draft to validate against. Defaults to `'2020-12'` to match\n * the spec; schemas authored against draft-07 should pass `'7'`.\n */\n draft?: SchemaDraft;\n}\n\nconst KEYWORD_WRAPPERS = new Set([\n \"properties\",\n \"items\",\n \"prefixItems\",\n \"$ref\",\n]);\n\nconst QUOTED_RE = /(['\"])((?:\\\\.|(?!\\1).)*?)\\1/g;\n\nfunction findQuoted(s: string): string[] {\n const out: string[] = [];\n let m: RegExpExecArray | null;\n QUOTED_RE.lastIndex = 0;\n while ((m = QUOTED_RE.exec(s)) !== null) {\n out.push(m[2]!);\n }\n return out;\n}\n\nfunction firstQuoted(s: string): string | undefined {\n const all = findQuoted(s);\n return all[0];\n}\n\nfunction allQuoted(s: string): string[] {\n return findQuoted(s);\n}\n\nconst NUMBER_RE = /-?\\d+(?:\\.\\d+)?/g;\n\nfunction extractNumbers(s: string): number[] {\n const out: number[] = [];\n let m: RegExpExecArray | null;\n NUMBER_RE.lastIndex = 0;\n while ((m = NUMBER_RE.exec(s)) !== null) {\n out.push(Number(m[0]));\n }\n return out;\n}\n\nfunction firstNumber(s: string): number | undefined {\n const nums = extractNumbers(s);\n return nums[0];\n}\n\nfunction stripPointerPrefix(p: string): string {\n return p.startsWith(\"#\") ? p.slice(1) : p;\n}\n\ninterface KeywordTransform {\n params: Record<string, unknown>;\n message: string | undefined;\n}\n\nfunction transformByKeyword(unit: OutputUnit): KeywordTransform {\n const { keyword, error } = unit;\n\n switch (keyword) {\n case \"required\": {\n const prop = firstQuoted(error);\n return {\n params: { missingProperty: prop ?? \"\" },\n message: prop\n ? `must have required property '${prop}'`\n : \"must have required property\",\n };\n }\n\n case \"type\": {\n const quoted = allQuoted(error);\n // cfworker emits `Instance type \"X\" is invalid. Expected \"Y\".` (single)\n // or `... Expected \"Y\" or \"Z\".` (union). Per AJV: `params.type` is the\n // expected type as a string; for unions it's comma-separated.\n const expected = quoted.slice(1).join(\",\") || quoted[0];\n const message = expected ? `must be ${expected}` : \"must be of expected type\";\n return {\n params: expected ? { type: expected } : {},\n message,\n };\n }\n\n case \"enum\": {\n // cfworker error: `Instance does not match any of [...].`\n const match = error.match(/\\[.*\\]/);\n let allowedValues: unknown[] = [];\n if (match) {\n try {\n allowedValues = JSON.parse(match[0]);\n } catch {\n allowedValues = [];\n }\n }\n return {\n params: { allowedValues },\n message: \"must be equal to one of the allowed values\",\n };\n }\n\n case \"const\":\n return {\n params: {},\n message: \"must be equal to constant\",\n };\n\n case \"minimum\": {\n const limit = extractNumbers(error)[1];\n return {\n params: { comparison: \">=\", limit: limit ?? 0 },\n message: `must be >= ${limit ?? 0}`,\n };\n }\n\n case \"exclusiveMinimum\": {\n const limit = extractNumbers(error)[1];\n return {\n params: { comparison: \">\", limit: limit ?? 0 },\n message: `must be > ${limit ?? 0}`,\n };\n }\n\n case \"maximum\": {\n const limit = extractNumbers(error)[1];\n return {\n params: { comparison: \"<=\", limit: limit ?? 0 },\n message: `must be <= ${limit ?? 0}`,\n };\n }\n\n case \"exclusiveMaximum\": {\n const limit = extractNumbers(error)[1];\n return {\n params: { comparison: \"<\", limit: limit ?? 0 },\n message: `must be < ${limit ?? 0}`,\n };\n }\n\n case \"minLength\": {\n const limit = firstNumber(error) ?? 0;\n return {\n params: { limit },\n message: `must NOT have fewer than ${limit} characters`,\n };\n }\n\n case \"maxLength\": {\n const limit = firstNumber(error) ?? 0;\n return {\n params: { limit },\n message: `must NOT have more than ${limit} characters`,\n };\n }\n\n case \"minItems\": {\n const limit = firstNumber(error) ?? 0;\n return {\n params: { limit },\n message: `must NOT have fewer than ${limit} items`,\n };\n }\n\n case \"maxItems\": {\n const limit = firstNumber(error) ?? 0;\n return {\n params: { limit },\n message: `must NOT have more than ${limit} items`,\n };\n }\n\n case \"pattern\": {\n const pattern = firstQuoted(error) ?? \"\";\n return {\n params: { pattern },\n message: `must match pattern \"${pattern}\"`,\n };\n }\n\n case \"format\": {\n const format = firstQuoted(error) ?? \"\";\n return {\n params: { format },\n message: `must match format \"${format}\"`,\n };\n }\n\n case \"multipleOf\": {\n // cfworker emits two numbers: the value and the divisor.\n const nums = extractNumbers(error);\n const multipleOf = nums[1] ?? nums[0] ?? 1;\n return {\n params: { multipleOf },\n message: `must be multiple of ${multipleOf}`,\n };\n }\n\n case \"uniqueItems\":\n return {\n params: {},\n message: \"must NOT have duplicate items\",\n };\n\n case \"additionalProperties\": {\n const additionalProperty = firstQuoted(error) ?? \"\";\n return {\n params: { additionalProperty },\n message: `must NOT have additional property '${additionalProperty}'`,\n };\n }\n\n case \"anyOf\":\n return { params: {}, message: \"must match a schema in anyOf\" };\n\n case \"oneOf\":\n return {\n params: { passingSchemas: null },\n message: \"must match exactly one schema in oneOf\",\n };\n\n case \"allOf\":\n return { params: {}, message: \"must match all schemas in allOf\" };\n\n case \"not\":\n return { params: {}, message: \"must NOT be valid against schema\" };\n\n default:\n return { params: {}, message: undefined };\n }\n}\n\n/**\n * Transform a single cfworker `OutputUnit` into an AJV-compatible\n * `ErrorObject`, or `null` if the unit is a structural wrapper that should\n * be filtered out (`properties` / `items` / `prefixItems` / `$ref`).\n *\n * Exported for unit testing.\n */\nexport function transformUnit(unit: OutputUnit): NoEvalErrorObject | null {\n if (KEYWORD_WRAPPERS.has(unit.keyword)) return null;\n\n const { params, message } = transformByKeyword(unit);\n\n return {\n instancePath: stripPointerPrefix(unit.instanceLocation),\n schemaPath: unit.keywordLocation,\n keyword: unit.keyword,\n params,\n message: message ?? unit.error,\n };\n}\n\n/**\n * Transform a cfworker `OutputUnit[]` into an AJV-compatible\n * `ErrorObject[]`, with structural wrappers filtered out.\n *\n * Exported for unit testing.\n */\nexport function transformErrors(units: OutputUnit[]): NoEvalErrorObject[] {\n const out: NoEvalErrorObject[] = [];\n for (const unit of units) {\n const transformed = transformUnit(unit);\n if (transformed !== null) out.push(transformed);\n }\n return out;\n}\n\nconst FROZEN_OPTS: Readonly<Record<string, unknown>> = Object.freeze({\n allErrors: true,\n verbose: true,\n errorDataPath: \"\",\n strict: false,\n});\n\n/**\n * Build a CSP-safe AJV-shaped validator backed by `@cfworker/json-schema`.\n *\n * Each `compile(schema)` call constructs a `Validator` and returns a\n * synchronous validator function. The validator function's `errors`\n * property is reassigned on every call, matching AJV's contract.\n *\n * Validators are memoized per-schema via a `WeakMap`, so JsonForms's\n * repeated `compile()` calls on prop changes don't re-parse the schema\n * graph each time.\n */\nexport function createNoEvalAjv(\n options: CreateNoEvalAjvOptions = {},\n): NoEvalAjv {\n const draft: SchemaDraft = options.draft ?? \"2020-12\";\n const cache = new WeakMap<object, NoEvalValidateFunction>();\n\n const compile = (schema: unknown): NoEvalValidateFunction => {\n if (schema && typeof schema === \"object\") {\n const cached = cache.get(schema as object);\n if (cached) return cached;\n }\n\n const validator = new Validator(schema as Schema | boolean, draft, false);\n\n const fn: NoEvalValidateFunction = ((data: unknown) => {\n const result = validator.validate(data);\n fn.errors = result.valid ? null : transformErrors(result.errors);\n return result.valid;\n }) as NoEvalValidateFunction;\n\n fn.errors = null;\n\n if (schema && typeof schema === \"object\") {\n cache.set(schema as object, fn);\n }\n return fn;\n };\n\n const facade: NoEvalAjv = {\n compile,\n addSchema: () => facade,\n getSchema: () => undefined,\n removeSchema: () => facade,\n addFormat: () => facade,\n addKeyword: () => facade,\n opts: FROZEN_OPTS,\n };\n\n return facade;\n}\n"],"names":[],"mappings":";AA2DA,MAAM,uCAAuB,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,MAAM,YAAY;AAElB,SAAS,WAAW,GAAqB;AACvC,QAAM,MAAgB,CAAA;AACtB,MAAI;AACJ,YAAU,YAAY;AACtB,UAAQ,IAAI,UAAU,KAAK,CAAC,OAAO,MAAM;AACvC,QAAI,KAAK,EAAE,CAAC,CAAE;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,YAAY,GAA+B;AAClD,QAAM,MAAM,WAAW,CAAC;AACxB,SAAO,IAAI,CAAC;AACd;AAEA,SAAS,UAAU,GAAqB;AACtC,SAAO,WAAW,CAAC;AACrB;AAEA,MAAM,YAAY;AAElB,SAAS,eAAe,GAAqB;AAC3C,QAAM,MAAgB,CAAA;AACtB,MAAI;AACJ,YAAU,YAAY;AACtB,UAAQ,IAAI,UAAU,KAAK,CAAC,OAAO,MAAM;AACvC,QAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;AAAA,EACvB;AACA,SAAO;AACT;AAEA,SAAS,YAAY,GAA+B;AAClD,QAAM,OAAO,eAAe,CAAC;AAC7B,SAAO,KAAK,CAAC;AACf;AAEA,SAAS,mBAAmB,GAAmB;AAC7C,SAAO,EAAE,WAAW,GAAG,IAAI,EAAE,MAAM,CAAC,IAAI;AAC1C;AAOA,SAAS,mBAAmB,MAAoC;AAC9D,QAAM,EAAE,SAAS,MAAA,IAAU;AAE3B,UAAQ,SAAA;AAAA,IACN,KAAK,YAAY;AACf,YAAM,OAAO,YAAY,KAAK;AAC9B,aAAO;AAAA,QACL,QAAQ,EAAE,iBAAiB,QAAQ,GAAA;AAAA,QACnC,SAAS,OACL,gCAAgC,IAAI,MACpC;AAAA,MAAA;AAAA,IAER;AAAA,IAEA,KAAK,QAAQ;AACX,YAAM,SAAS,UAAU,KAAK;AAI9B,YAAM,WAAW,OAAO,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,OAAO,CAAC;AACtD,YAAM,UAAU,WAAW,WAAW,QAAQ,KAAK;AACnD,aAAO;AAAA,QACL,QAAQ,WAAW,EAAE,MAAM,SAAA,IAAa,CAAA;AAAA,QACxC;AAAA,MAAA;AAAA,IAEJ;AAAA,IAEA,KAAK,QAAQ;AAEX,YAAM,QAAQ,MAAM,MAAM,QAAQ;AAClC,UAAI,gBAA2B,CAAA;AAC/B,UAAI,OAAO;AACT,YAAI;AACF,0BAAgB,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,QACrC,QAAQ;AACN,0BAAgB,CAAA;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,QACL,QAAQ,EAAE,cAAA;AAAA,QACV,SAAS;AAAA,MAAA;AAAA,IAEb;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,CAAA;AAAA,QACR,SAAS;AAAA,MAAA;AAAA,IAGb,KAAK,WAAW;AACd,YAAM,QAAQ,eAAe,KAAK,EAAE,CAAC;AACrC,aAAO;AAAA,QACL,QAAQ,EAAE,YAAY,MAAM,OAAO,SAAS,EAAA;AAAA,QAC5C,SAAS,cAAc,SAAS,CAAC;AAAA,MAAA;AAAA,IAErC;AAAA,IAEA,KAAK,oBAAoB;AACvB,YAAM,QAAQ,eAAe,KAAK,EAAE,CAAC;AACrC,aAAO;AAAA,QACL,QAAQ,EAAE,YAAY,KAAK,OAAO,SAAS,EAAA;AAAA,QAC3C,SAAS,aAAa,SAAS,CAAC;AAAA,MAAA;AAAA,IAEpC;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,QAAQ,eAAe,KAAK,EAAE,CAAC;AACrC,aAAO;AAAA,QACL,QAAQ,EAAE,YAAY,MAAM,OAAO,SAAS,EAAA;AAAA,QAC5C,SAAS,cAAc,SAAS,CAAC;AAAA,MAAA;AAAA,IAErC;AAAA,IAEA,KAAK,oBAAoB;AACvB,YAAM,QAAQ,eAAe,KAAK,EAAE,CAAC;AACrC,aAAO;AAAA,QACL,QAAQ,EAAE,YAAY,KAAK,OAAO,SAAS,EAAA;AAAA,QAC3C,SAAS,aAAa,SAAS,CAAC;AAAA,MAAA;AAAA,IAEpC;AAAA,IAEA,KAAK,aAAa;AAChB,YAAM,QAAQ,YAAY,KAAK,KAAK;AACpC,aAAO;AAAA,QACL,QAAQ,EAAE,MAAA;AAAA,QACV,SAAS,4BAA4B,KAAK;AAAA,MAAA;AAAA,IAE9C;AAAA,IAEA,KAAK,aAAa;AAChB,YAAM,QAAQ,YAAY,KAAK,KAAK;AACpC,aAAO;AAAA,QACL,QAAQ,EAAE,MAAA;AAAA,QACV,SAAS,2BAA2B,KAAK;AAAA,MAAA;AAAA,IAE7C;AAAA,IAEA,KAAK,YAAY;AACf,YAAM,QAAQ,YAAY,KAAK,KAAK;AACpC,aAAO;AAAA,QACL,QAAQ,EAAE,MAAA;AAAA,QACV,SAAS,4BAA4B,KAAK;AAAA,MAAA;AAAA,IAE9C;AAAA,IAEA,KAAK,YAAY;AACf,YAAM,QAAQ,YAAY,KAAK,KAAK;AACpC,aAAO;AAAA,QACL,QAAQ,EAAE,MAAA;AAAA,QACV,SAAS,2BAA2B,KAAK;AAAA,MAAA;AAAA,IAE7C;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,UAAU,YAAY,KAAK,KAAK;AACtC,aAAO;AAAA,QACL,QAAQ,EAAE,QAAA;AAAA,QACV,SAAS,uBAAuB,OAAO;AAAA,MAAA;AAAA,IAE3C;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,SAAS,YAAY,KAAK,KAAK;AACrC,aAAO;AAAA,QACL,QAAQ,EAAE,OAAA;AAAA,QACV,SAAS,sBAAsB,MAAM;AAAA,MAAA;AAAA,IAEzC;AAAA,IAEA,KAAK,cAAc;AAEjB,YAAM,OAAO,eAAe,KAAK;AACjC,YAAM,aAAa,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK;AACzC,aAAO;AAAA,QACL,QAAQ,EAAE,WAAA;AAAA,QACV,SAAS,uBAAuB,UAAU;AAAA,MAAA;AAAA,IAE9C;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,CAAA;AAAA,QACR,SAAS;AAAA,MAAA;AAAA,IAGb,KAAK,wBAAwB;AAC3B,YAAM,qBAAqB,YAAY,KAAK,KAAK;AACjD,aAAO;AAAA,QACL,QAAQ,EAAE,mBAAA;AAAA,QACV,SAAS,sCAAsC,kBAAkB;AAAA,MAAA;AAAA,IAErE;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,QAAQ,IAAI,SAAS,+BAAA;AAAA,IAEhC,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,EAAE,gBAAgB,KAAA;AAAA,QAC1B,SAAS;AAAA,MAAA;AAAA,IAGb,KAAK;AACH,aAAO,EAAE,QAAQ,IAAI,SAAS,kCAAA;AAAA,IAEhC,KAAK;AACH,aAAO,EAAE,QAAQ,IAAI,SAAS,mCAAA;AAAA,IAEhC;AACE,aAAO,EAAE,QAAQ,IAAI,SAAS,OAAA;AAAA,EAAU;AAE9C;AASO,SAAS,cAAc,MAA4C;AACxE,MAAI,iBAAiB,IAAI,KAAK,OAAO,EAAG,QAAO;AAE/C,QAAM,EAAE,QAAQ,YAAY,mBAAmB,IAAI;AAEnD,SAAO;AAAA,IACL,cAAc,mBAAmB,KAAK,gBAAgB;AAAA,IACtD,YAAY,KAAK;AAAA,IACjB,SAAS,KAAK;AAAA,IACd;AAAA,IACA,SAAS,WAAW,KAAK;AAAA,EAAA;AAE7B;AAQO,SAAS,gBAAgB,OAA0C;AACxE,QAAM,MAA2B,CAAA;AACjC,aAAW,QAAQ,OAAO;AACxB,UAAM,cAAc,cAAc,IAAI;AACtC,QAAI,gBAAgB,KAAM,KAAI,KAAK,WAAW;AAAA,EAChD;AACA,SAAO;AACT;AAEA,MAAM,cAAiD,OAAO,OAAO;AAAA,EACnE,WAAW;AAAA,EACX,SAAS;AAAA,EACT,eAAe;AAAA,EACf,QAAQ;AACV,CAAC;AAaM,SAAS,gBACd,UAAkC,IACvB;AACX,QAAM,QAAqB,QAAQ,SAAS;AAC5C,QAAM,4BAAY,QAAA;AAElB,QAAM,UAAU,CAAC,WAA4C;AAC3D,QAAI,UAAU,OAAO,WAAW,UAAU;AACxC,YAAM,SAAS,MAAM,IAAI,MAAgB;AACzC,UAAI,OAAQ,QAAO;AAAA,IACrB;AAEA,UAAM,YAAY,IAAI,UAAU,QAA4B,OAAO,KAAK;AAExE,UAAM,MAA8B,CAAC,SAAkB;AACrD,YAAM,SAAS,UAAU,SAAS,IAAI;AACtC,SAAG,SAAS,OAAO,QAAQ,OAAO,gBAAgB,OAAO,MAAM;AAC/D,aAAO,OAAO;AAAA,IAChB;AAEA,OAAG,SAAS;AAEZ,QAAI,UAAU,OAAO,WAAW,UAAU;AACxC,YAAM,IAAI,QAAkB,EAAE;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAoB;AAAA,IACxB;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,IACjB,cAAc,MAAM;AAAA,IACpB,WAAW,MAAM;AAAA,IACjB,YAAY,MAAM;AAAA,IAClB,MAAM;AAAA,EAAA;AAGR,SAAO;AACT;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useProjection.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProjection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAQnE,UAAU,iBAAiB;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CACzE;AA8FD,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,aAAa,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,gEAAgE;IAEhE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClD,8DAA8D;IAC9D,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC;IACvB,sFAAsF;IACtF,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC/B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GACnD,gBAAgB,CAyFlB"}
1
+ {"version":3,"file":"useProjection.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProjection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AASnE,UAAU,iBAAiB;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CACzE;AAqGD,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,aAAa,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,gEAAgE;IAEhE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClD,8DAA8D;IAC9D,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC;IACvB,sFAAsF;IACtF,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC/B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GACnD,gBAAgB,CAgGlB"}
@@ -1,25 +1,28 @@
1
1
  import { computed, inject } from "vue";
2
2
  import { getProjectedValue, getProjectedSchema, parseProjectionPath, setProjectedValue } from "../../core/projection.js";
3
+ import { deref } from "../../core/refs.js";
3
4
  function resolveLabel(ctrl, schemaTitle, required) {
4
5
  const base = ctrl.uischema?.options?.label ?? schemaTitle ?? ctrl.label ?? "";
5
6
  if (!base) return base;
6
7
  return required ? `${base} *` : base;
7
8
  }
8
- function isProjectedFieldRequired(schema, path) {
9
+ function isProjectedFieldRequired(schema, path, root) {
9
10
  const segments = parseProjectionPath(path);
10
11
  if (segments.length === 0) return false;
11
- let current = schema;
12
+ const rootSchema = root ?? schema;
13
+ let current = deref(schema, rootSchema);
12
14
  for (let i = 0; i < segments.length - 1; i++) {
13
15
  const seg = segments[i];
14
16
  if (typeof seg === "number") {
15
- current = current?.items;
17
+ current = deref(current?.items, rootSchema);
16
18
  } else {
17
- current = current?.properties?.[seg];
19
+ current = deref(current?.properties?.[seg], rootSchema);
18
20
  }
19
21
  if (!current) return false;
20
22
  }
21
23
  const last = segments[segments.length - 1];
22
24
  if (typeof last !== "string") return false;
25
+ current = deref(current, rootSchema);
23
26
  return Array.isArray(current?.required) && current.required.includes(last);
24
27
  }
25
28
  function normalizeErrors(errors) {
@@ -57,10 +60,7 @@ function useProjection(control, handleChange) {
57
60
  )
58
61
  };
59
62
  }
60
- const jsonforms = inject(
61
- "jsonforms",
62
- null
63
- );
63
+ const jsonforms = inject("jsonforms", null);
64
64
  const fullProjectedPath = control.value.path + "." + projection;
65
65
  const projectedData = computed(
66
66
  () => getProjectedValue(control.value.data, projection)
@@ -69,7 +69,11 @@ function useProjection(control, handleChange) {
69
69
  () => getProjectedSchema(control.value.schema, projection)
70
70
  );
71
71
  const projectedRequired = computed(
72
- () => isProjectedFieldRequired(control.value.schema, projection)
72
+ () => isProjectedFieldRequired(
73
+ control.value.schema,
74
+ projection,
75
+ jsonforms?.core?.schema ?? control.value.schema
76
+ )
73
77
  );
74
78
  const label = computed(
75
79
  () => resolveLabel(
@@ -1 +1 @@
1
- {"version":3,"file":"useProjection.js","sources":["../../../src/vue/composables/useProjection.ts"],"sourcesContent":["import { computed, inject, type ComputedRef, type Ref } from \"vue\";\nimport {\n getProjectedValue,\n setProjectedValue,\n getProjectedSchema,\n parseProjectionPath,\n} from \"../../core/projection\";\n\ninterface ProjectionControl {\n data: unknown;\n path: string;\n errors: string;\n label?: string;\n required?: boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>;\n uischema: { options?: { projection?: string; [key: string]: unknown } };\n}\n\n// Minimal AJV ErrorObject shape for filtering\ninterface ErrorLike {\n instancePath?: string;\n keyword?: string;\n message?: string;\n params?: { missingProperty?: string };\n}\n\n/**\n * Resolve the display label for a control.\n * Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.\n * Appends a trailing asterisk when the control is for a required property.\n */\nfunction resolveLabel(\n ctrl: ProjectionControl,\n schemaTitle?: string,\n required?: boolean,\n): string {\n const base =\n (ctrl.uischema?.options?.label as string) ??\n schemaTitle ??\n ctrl.label ??\n \"\";\n if (!base) return base;\n return required ? `${base} *` : base;\n}\n\n/**\n * Determine whether the leaf of a projection path is listed in its parent\n * schema's `required` array. Numeric leaf segments (array indices) are not\n * considered \"required properties\".\n */\nfunction isProjectedFieldRequired(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>,\n path: string,\n): boolean {\n const segments = parseProjectionPath(path);\n if (segments.length === 0) return false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: Record<string, any> = schema;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n if (typeof seg === \"number\") {\n current = current?.items;\n } else {\n current = current?.properties?.[seg];\n }\n if (!current) return false;\n }\n const last = segments[segments.length - 1];\n if (typeof last !== \"string\") return false;\n return Array.isArray(current?.required) && current.required.includes(last);\n}\n\n/**\n * Normalize AJV error message fragments into user-friendly text.\n * e.g. \"is a required property\" → \"is required\"\n */\nfunction normalizeErrors(errors: string): string {\n if (!errors) return errors;\n return errors\n .replace(/is a required property/g, \"is required\")\n .replace(/must have required property '[^']*'/g, \"is required\");\n}\n\n/**\n * Prefix each error message line with the field label so that AJV fragments\n * like \"is required\" become \"Name is required\".\n */\nfunction prefixErrors(label: string, errors: string): string {\n if (!label || !errors) return errors;\n return errors\n .split(\"\\n\")\n .map((line) => `${label} ${line}`)\n .join(\"\\n\");\n}\n\n/**\n * Convert an AJV ErrorObject's instancePath to a dot-separated control path.\n * Replicates the logic from @jsonforms/core getControlPath.\n */\nfunction getErrorPath(error: ErrorLike): string {\n let p = (error.instancePath || \"\").replace(/\\//g, \".\").replace(/^\\./, \"\");\n if (error.keyword === \"required\" && error.params?.missingProperty) {\n p = p\n ? p + \".\" + error.params.missingProperty\n : error.params.missingProperty;\n }\n return p;\n}\n\nexport interface ProjectionResult {\n /** The value at the projected path (for rendering) */\n projectedData: ComputedRef<unknown>;\n /** The schema at the projected path (for renderer selection) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n projectedSchema: ComputedRef<Record<string, any>>;\n /** Wrapped handleChange that writes through the projection */\n handleProjectedChange: (path: string, value: unknown) => void;\n /** Whether projection is active */\n hasProjection: boolean;\n /** Resolved display label (options.label → projected schema title → control.label) */\n projectedLabel: ComputedRef<string>;\n /** Error string combining base-path and projected sub-path errors */\n projectedErrors: ComputedRef<string>;\n}\n\n/**\n * Composable that wraps a JSON Forms control with projection support.\n *\n * When `options.projection` is set on the uischema, this composable:\n * - Reads the projected sub-value from the control data\n * - Resolves the projected sub-schema for renderer type resolution\n * - Wraps handleChange to write back through the projection path (preserving siblings)\n *\n * When no projection is set, it passes through control data/schema/handleChange unchanged.\n */\nexport function useProjection(\n control: Ref<ProjectionControl>,\n handleChange: (path: string, value: unknown) => void,\n): ProjectionResult {\n const projection = control.value.uischema?.options?.projection as\n | string\n | undefined;\n\n if (!projection) {\n const label = computed(() =>\n resolveLabel(control.value, undefined, control.value.required),\n );\n return {\n projectedData: computed(() => control.value.data),\n projectedSchema: computed(() => control.value.schema),\n handleProjectedChange: handleChange,\n hasProjection: false,\n projectedLabel: label,\n projectedErrors: computed(() =>\n prefixErrors(\n label.value.replace(/\\*$/, \"\").trim(),\n normalizeErrors(control.value.errors),\n ),\n ),\n };\n }\n\n // Inject JSONForms state to access raw AJV errors for projected sub-paths.\n // control.errors only contains errors at the exact control path (e.g. \"data_rates\"),\n // but projected fields need errors at the full path (e.g. \"data_rates.0.video_rate_usd\").\n const jsonforms = inject<{ core?: { errors?: ErrorLike[] } } | null>(\n \"jsonforms\",\n null,\n );\n\n const fullProjectedPath = control.value.path + \".\" + projection;\n\n const projectedData = computed(() =>\n getProjectedValue(control.value.data, projection),\n );\n\n const projectedSchema = computed(() =>\n getProjectedSchema(control.value.schema, projection),\n );\n\n const projectedRequired = computed(() =>\n isProjectedFieldRequired(control.value.schema, projection),\n );\n\n const label = computed(() =>\n resolveLabel(\n control.value,\n projectedSchema.value?.title,\n projectedRequired.value,\n ),\n );\n\n const projectedErrors = computed(() => {\n const baseErrors = normalizeErrors(control.value.errors || \"\");\n\n const rawErrors = jsonforms?.core?.errors ?? [];\n const matching = rawErrors.filter(\n (err) => getErrorPath(err) === fullProjectedPath,\n );\n\n let errStr: string;\n if (matching.length === 0) {\n errStr = baseErrors;\n } else {\n const projMsg = matching\n .map((e) => (e.keyword === \"required\" ? \"is required\" : e.message))\n .filter(Boolean)\n .join(\"\\n\");\n errStr = [baseErrors, projMsg].filter(Boolean).join(\"\\n\");\n }\n\n return prefixErrors(label.value.replace(/\\*$/, \"\").trim(), errStr);\n });\n\n const handleProjectedChange = (path: string, value: unknown) => {\n const fullValue = setProjectedValue(control.value.data, projection, value);\n handleChange(path, fullValue);\n };\n\n return {\n projectedData,\n projectedSchema,\n handleProjectedChange,\n hasProjection: true,\n projectedLabel: label,\n projectedErrors,\n };\n}\n"],"names":["label"],"mappings":"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"}
1
+ {"version":3,"file":"useProjection.js","sources":["../../../src/vue/composables/useProjection.ts"],"sourcesContent":["import { computed, inject, type ComputedRef, type Ref } from \"vue\";\nimport {\n getProjectedValue,\n setProjectedValue,\n getProjectedSchema,\n parseProjectionPath,\n} from \"../../core/projection\";\nimport { deref } from \"../../core/refs\";\n\ninterface ProjectionControl {\n data: unknown;\n path: string;\n errors: string;\n label?: string;\n required?: boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>;\n uischema: { options?: { projection?: string; [key: string]: unknown } };\n}\n\n// Minimal AJV ErrorObject shape for filtering\ninterface ErrorLike {\n instancePath?: string;\n keyword?: string;\n message?: string;\n params?: { missingProperty?: string };\n}\n\n/**\n * Resolve the display label for a control.\n * Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.\n * Appends a trailing asterisk when the control is for a required property.\n */\nfunction resolveLabel(\n ctrl: ProjectionControl,\n schemaTitle?: string,\n required?: boolean,\n): string {\n const base =\n (ctrl.uischema?.options?.label as string) ??\n schemaTitle ??\n ctrl.label ??\n \"\";\n if (!base) return base;\n return required ? `${base} *` : base;\n}\n\n/**\n * Determine whether the leaf of a projection path is listed in its parent\n * schema's `required` array. Numeric leaf segments (array indices) are not\n * considered \"required properties\".\n *\n * Dereferences `$ref` at every step against `root` (defaulting to `schema`)\n * so that schemas like `items: { $ref: '#/$defs/Foo' }` resolve correctly.\n */\nfunction isProjectedFieldRequired(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>,\n path: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n root?: Record<string, any>,\n): boolean {\n const segments = parseProjectionPath(path);\n if (segments.length === 0) return false;\n const rootSchema = root ?? schema;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: Record<string, any> | undefined = deref(schema, rootSchema);\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n if (typeof seg === \"number\") {\n current = deref(current?.items, rootSchema);\n } else {\n current = deref(current?.properties?.[seg], rootSchema);\n }\n if (!current) return false;\n }\n const last = segments[segments.length - 1];\n if (typeof last !== \"string\") return false;\n current = deref(current, rootSchema);\n return Array.isArray(current?.required) && current.required.includes(last);\n}\n\n/**\n * Normalize AJV error message fragments into user-friendly text.\n * e.g. \"is a required property\" → \"is required\"\n */\nfunction normalizeErrors(errors: string): string {\n if (!errors) return errors;\n return errors\n .replace(/is a required property/g, \"is required\")\n .replace(/must have required property '[^']*'/g, \"is required\");\n}\n\n/**\n * Prefix each error message line with the field label so that AJV fragments\n * like \"is required\" become \"Name is required\".\n */\nfunction prefixErrors(label: string, errors: string): string {\n if (!label || !errors) return errors;\n return errors\n .split(\"\\n\")\n .map((line) => `${label} ${line}`)\n .join(\"\\n\");\n}\n\n/**\n * Convert an AJV ErrorObject's instancePath to a dot-separated control path.\n * Replicates the logic from @jsonforms/core getControlPath.\n */\nfunction getErrorPath(error: ErrorLike): string {\n let p = (error.instancePath || \"\").replace(/\\//g, \".\").replace(/^\\./, \"\");\n if (error.keyword === \"required\" && error.params?.missingProperty) {\n p = p\n ? p + \".\" + error.params.missingProperty\n : error.params.missingProperty;\n }\n return p;\n}\n\nexport interface ProjectionResult {\n /** The value at the projected path (for rendering) */\n projectedData: ComputedRef<unknown>;\n /** The schema at the projected path (for renderer selection) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n projectedSchema: ComputedRef<Record<string, any>>;\n /** Wrapped handleChange that writes through the projection */\n handleProjectedChange: (path: string, value: unknown) => void;\n /** Whether projection is active */\n hasProjection: boolean;\n /** Resolved display label (options.label → projected schema title → control.label) */\n projectedLabel: ComputedRef<string>;\n /** Error string combining base-path and projected sub-path errors */\n projectedErrors: ComputedRef<string>;\n}\n\n/**\n * Composable that wraps a JSON Forms control with projection support.\n *\n * When `options.projection` is set on the uischema, this composable:\n * - Reads the projected sub-value from the control data\n * - Resolves the projected sub-schema for renderer type resolution\n * - Wraps handleChange to write back through the projection path (preserving siblings)\n *\n * When no projection is set, it passes through control data/schema/handleChange unchanged.\n */\nexport function useProjection(\n control: Ref<ProjectionControl>,\n handleChange: (path: string, value: unknown) => void,\n): ProjectionResult {\n const projection = control.value.uischema?.options?.projection as\n | string\n | undefined;\n\n if (!projection) {\n const label = computed(() =>\n resolveLabel(control.value, undefined, control.value.required),\n );\n return {\n projectedData: computed(() => control.value.data),\n projectedSchema: computed(() => control.value.schema),\n handleProjectedChange: handleChange,\n hasProjection: false,\n projectedLabel: label,\n projectedErrors: computed(() =>\n prefixErrors(\n label.value.replace(/\\*$/, \"\").trim(),\n normalizeErrors(control.value.errors),\n ),\n ),\n };\n }\n\n // Inject JSONForms state to access raw AJV errors for projected sub-paths,\n // and the root schema so that `$ref` resolution inside the projected slice\n // can find `$defs` (which live at the root, not on the control's schema).\n const jsonforms = inject<{\n core?: {\n errors?: ErrorLike[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema?: Record<string, any>;\n };\n } | null>(\"jsonforms\", null);\n\n const fullProjectedPath = control.value.path + \".\" + projection;\n\n const projectedData = computed(() =>\n getProjectedValue(control.value.data, projection),\n );\n\n const projectedSchema = computed(() =>\n getProjectedSchema(control.value.schema, projection),\n );\n\n const projectedRequired = computed(() =>\n isProjectedFieldRequired(\n control.value.schema,\n projection,\n jsonforms?.core?.schema ?? control.value.schema,\n ),\n );\n\n const label = computed(() =>\n resolveLabel(\n control.value,\n projectedSchema.value?.title,\n projectedRequired.value,\n ),\n );\n\n const projectedErrors = computed(() => {\n const baseErrors = normalizeErrors(control.value.errors || \"\");\n\n const rawErrors = jsonforms?.core?.errors ?? ([] as ErrorLike[]);\n const matching = rawErrors.filter(\n (err) => getErrorPath(err) === fullProjectedPath,\n );\n\n let errStr: string;\n if (matching.length === 0) {\n errStr = baseErrors;\n } else {\n const projMsg = matching\n .map((e) => (e.keyword === \"required\" ? \"is required\" : e.message))\n .filter(Boolean)\n .join(\"\\n\");\n errStr = [baseErrors, projMsg].filter(Boolean).join(\"\\n\");\n }\n\n return prefixErrors(label.value.replace(/\\*$/, \"\").trim(), errStr);\n });\n\n const handleProjectedChange = (path: string, value: unknown) => {\n const fullValue = setProjectedValue(control.value.data, projection, value);\n handleChange(path, fullValue);\n };\n\n return {\n projectedData,\n projectedSchema,\n handleProjectedChange,\n hasProjection: true,\n projectedLabel: label,\n projectedErrors,\n };\n}\n"],"names":["label"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narrative.io/jsonforms-provider-protocols",
3
- "version": "3.0.0-beta.19",
3
+ "version": "3.0.0-beta.20",
4
4
  "description": "Dynamic data provider capabilities for JSONForms with Vue 3 integration",
5
5
  "type": "module",
6
6
  "author": "Narrative I/O",
@@ -47,6 +47,10 @@
47
47
  "import": "./dist/protocols/rest_api.js",
48
48
  "types": "./dist/protocols/rest_api.d.ts"
49
49
  },
50
+ "./no-eval-ajv": {
51
+ "import": "./dist/no-eval-ajv.js",
52
+ "types": "./dist/no-eval-ajv.d.ts"
53
+ },
50
54
  "./style.css": "./dist/jsonforms-provider-protocols.css"
51
55
  },
52
56
  "files": [
@@ -107,5 +111,7 @@
107
111
  "@jsonforms/vue": "^3.6.0",
108
112
  "@jsonforms/vue-vanilla": "^3.6.0"
109
113
  },
110
- "dependencies": {}
114
+ "dependencies": {
115
+ "@cfworker/json-schema": "4.1.1"
116
+ }
111
117
  }
@@ -41,12 +41,10 @@ export function initFormDataFromSchema(
41
41
  }
42
42
  }
43
43
 
44
- debugLog("[initFormData] initFormDataFromSchema", { schema, seed, output: base });
45
44
  return base;
46
45
  }
47
46
 
48
47
  import { resolveRef } from "./refs";
49
- import { debugLog } from "../debug/overlay";
50
48
 
51
49
  /**
52
50
  * Initialize a single property value based on its schema definition.
@@ -1,8 +1,4 @@
1
- import {
2
- deref as derefSchema,
3
- tryCombinatorBranches,
4
- } from "./refs";
5
- import { debugLog } from "../debug/overlay";
1
+ import { deref as derefSchema, tryCombinatorBranches } from "./refs";
6
2
 
7
3
  /**
8
4
  * Projection utilities for navigating complex data structures
@@ -120,10 +116,7 @@ export function getProjectedSchema(
120
116
 
121
117
  for (const seg of segments) {
122
118
  current = derefSchema(current, schema);
123
- if (!current) {
124
- debugLog("[projection] empty (deref miss)", { path, segment: seg, rootSchema: schema });
125
- return {};
126
- }
119
+ if (!current) return {};
127
120
 
128
121
  const navigate = (
129
122
  node: Record<string, unknown>,
@@ -145,15 +138,10 @@ export function getProjectedSchema(
145
138
  if (next === undefined) {
146
139
  next = tryCombinatorBranches(current, schema, navigate);
147
140
  }
148
- if (!next) {
149
- debugLog("[projection] empty (segment unresolved)", { path, segment: seg, current, rootSchema: schema });
150
- return {};
151
- }
141
+ if (!next) return {};
152
142
  current = next;
153
143
  }
154
144
 
155
145
  const resolved = derefSchema(current, schema);
156
- const out = resolved ?? {};
157
- debugLog("[projection] getProjectedSchema", { path, output: out, rootSchema: schema });
158
- return out;
146
+ return resolved ?? {};
159
147
  }
@@ -1,5 +1,4 @@
1
1
  import { deepDeref, deref, tryCombinatorBranches } from "./refs";
2
- import { debugLog } from "../debug/overlay";
3
2
 
4
3
  /**
5
4
  * Resolve a JSON Forms scope path to its schema within a root schema.
@@ -22,18 +21,11 @@ export function resolveScopeSchema(
22
21
  rootSchema: Record<string, any>,
23
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
23
  ): Record<string, any> | undefined {
25
- if (!scope || !rootSchema) {
26
- debugLog("[resolveScope] undefined (empty input)", { scope, rootSchema });
27
- return undefined;
28
- }
24
+ if (!scope || !rootSchema) return undefined;
29
25
 
30
26
  // Remove the leading "#/" and split into segments
31
27
  const path = scope.replace(/^#\/?/, "");
32
- if (!path) {
33
- const out = deepDeref(rootSchema, rootSchema);
34
- debugLog("[resolveScope] root deepDeref", { scope, output: out, rootSchema });
35
- return out;
36
- }
28
+ if (!path) return deepDeref(rootSchema, rootSchema);
37
29
 
38
30
  const segments = path.split("/");
39
31
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -41,10 +33,7 @@ export function resolveScopeSchema(
41
33
 
42
34
  for (const segment of segments) {
43
35
  current = deref(current, rootSchema);
44
- if (!current || typeof current !== "object") {
45
- debugLog("[resolveScope] undefined (deref miss)", { scope, segment, rootSchema });
46
- return undefined;
47
- }
36
+ if (!current || typeof current !== "object") return undefined;
48
37
 
49
38
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
39
  const navigate = (node: Record<string, any>): unknown => {
@@ -57,14 +46,9 @@ export function resolveScopeSchema(
57
46
  if (next === undefined) {
58
47
  next = tryCombinatorBranches(current, rootSchema, navigate);
59
48
  }
60
- if (next === undefined) {
61
- debugLog("[resolveScope] undefined (segment unresolved)", { scope, segment, current, rootSchema });
62
- return undefined;
63
- }
49
+ if (next === undefined) return undefined;
64
50
  current = next;
65
51
  }
66
52
 
67
- const out = deepDeref(current, rootSchema);
68
- debugLog("[resolveScope] resolveScopeSchema", { scope, output: out, rootSchema });
69
- return out;
53
+ return deepDeref(current, rootSchema);
70
54
  }
package/src/index.ts CHANGED
@@ -3,8 +3,6 @@ import { cache as globalCache } from "./core/cache";
3
3
  import { registry as globalRegistry } from "./core/registry";
4
4
  import type { Protocol, AuthConfig } from "./core/types";
5
5
 
6
- console.log("[jsonforms-provider-protocols] loaded v2.10.0 (symlink)");
7
-
8
6
  export { cache } from "./core/cache";
9
7
  export * from "./core/jsonpath";
10
8
  export { registry } from "./core/registry";
@@ -19,6 +17,19 @@ export { initFormDataFromSchema } from "./core/initFormData";
19
17
  // Protocol exports
20
18
  export { RestApiProtocol } from "./protocols/rest_api";
21
19
 
20
+ // CSP-safe validator
21
+ export {
22
+ createNoEvalAjv,
23
+ transformUnit,
24
+ transformErrors,
25
+ } from "./no-eval-ajv";
26
+ export type {
27
+ NoEvalAjv,
28
+ NoEvalErrorObject,
29
+ NoEvalValidateFunction,
30
+ CreateNoEvalAjvOptions,
31
+ } from "./no-eval-ajv";
32
+
22
33
  // Vue exports - using named imports to avoid potential bundling issues
23
34
  export {
24
35
  providerRenderers,