Skip to content

Commit

Permalink
better exporting of types (#43)
Browse files Browse the repository at this point in the history
* feat: types/index.d.ts for better exporting of types ({JSON,Protobuf}Schema)

* feat: use latest version as default export of types

* feat: export every schemaVersion but with last version without number

* chore: bugfix after merge from master

---------

Co-authored-by: Tomás Ciccola <tciccola@digital-democracy.com>
  • Loading branch information
tomasciccola and Tomás Ciccola authored Apr 13, 2023
1 parent 3fdb759 commit a3f79e0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
19 changes: 9 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
* @module mapeo-schema
*/
import * as cenc from 'compact-encoding'
import * as JSONSchemas from './dist/schemas.js'
import * as Schemas from './dist/schemas.js'
import * as ProtobufSchemas from './types/proto/index.js'
import schemasPrefix from './schemasPrefix.js'
import { inheritsFromCommon, formatSchemaKey } from './utils.js'

const dataTypeIdSize = 6
const schemaVersionSize = 2

/**
* @param {import('./types/schema/index').MapeoRecord} obj - Object to be encoded
* @returns {import('./types/proto/index').ProtobufSchemas}
* @param {import('./types').JSONSchema} obj - Object to be encoded
* @returns {import('./types').ProtobufSchema}
*/
const jsonSchemaToProto = (obj) => {
const commonKeys = [
Expand Down Expand Up @@ -49,12 +48,12 @@ const jsonSchemaToProto = (obj) => {
}

/**
* @param {import('./types/proto/index').ProtobufSchemas} protobufObj
* @param {import('./types').ProtobufSchema} protobufObj
* @param {Object} obj
* @param {Number} obj.schemaVersion
* @param {String} obj.schemaType
* @param {String} obj.version
* @returns {import('./types/schema/index').MapeoRecord}
* @returns {import('./types').JSONSchema}
*/
const protoToJsonSchema = (
protobufObj,
Expand Down Expand Up @@ -117,7 +116,7 @@ export const decodeBlockPrefix = (buf) => {

/**
* Validate an object against the schema type
* @param {import('./types/schema/index').MapeoRecord} obj - Object to be encoded
* @param {import('./types').JSONSchema} obj - Object to be encoded
* @returns {Boolean} indicating if the object is valid
*/
export const validate = (obj) => {
Expand All @@ -138,15 +137,15 @@ export const validate = (obj) => {
delete obj.schemaType
}

const validatefn = JSONSchemas[key]
const validatefn = Schemas[key]
const isValid = validatefn(obj)
if (!isValid) throw new Error(JSON.stringify(validatefn.errors, null, 4))
return isValid
}

/**
* Encode a an object validated against a schema as a binary protobuf to send to an hypercore.
* @param {import('./types/schema/index').MapeoRecord} obj - Object to be encoded
* @param {import('./types').JSONSchema} obj - Object to be encoded
* @returns {Buffer} protobuf encoded buffer with dataTypeIdSize + schemaVersionSize bytes prepended, one for the type of record and the other for the version of the schema */
export const encode = (obj) => {
const key = formatSchemaKey(obj.schemaType, obj.schemaVersion)
Expand All @@ -171,7 +170,7 @@ export const encode = (obj) => {
/**
* Decode a Buffer as an object validated against the corresponding schema
* @param {Buffer} buf - Buffer to be decoded
* @returns {import('./types/schema/index').MapeoRecord}
* @returns {import('./types').JSONSchema}
* */
export const decode = (buf, { coreId, seq }) => {
const { dataTypeId, schemaVersion } = decodeBlockPrefix(buf)
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"description": "JSON schema and flow types for Mapeo",
"main": "src/index.js",
"type": "module",
"exports": {
"types/": "./types/index.d.ts",
"types/schema": "./types/schema/index.d.ts",
"types/proto": "./types/proto/index.d.ts"
},
"scripts": {
"example": "node examples/schema_test.js",
"protobuf": "buf generate ./proto",
Expand Down
68 changes: 56 additions & 12 deletions scripts/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// This script is use to generate various files to be used at runtime:
// * dist/schemas.js - all the validating functions for jsonSchema
// * types/schema/index.d.ts - Union type for all the JsonSchemas
// * types/schema/index.d.ts - Union type for all the ProtobufSchemas
// * types/proto/index.d.ts - Union type for all the ProtobufSchemas
// * types/proto/index.js - Exports all protobufs from one file
// * types/index.d.ts - re-exports JSONSchema and ProtobufSchema types for better importing

import fs from 'node:fs'
import path from 'path'
Expand Down Expand Up @@ -51,20 +52,35 @@ const ajv = new Ajv({
})
ajv.addKeyword('meta:enum')

// generate code
// generate validation code
let schemaValidations = standaloneCode(ajv, schemaExports)

const dist = path.join(__dirname, '../dist')
if (!fs.existsSync(dist)) {
fs.mkdirSync(dist)
}
// dump all to file

// dist/schemas.js
fs.writeFileSync(
path.join(__dirname, '../dist', 'schemas.js'),
schemaValidations
)

// generate types/schema/index.d.ts
const latestSchemaVersions = schemas.reduce(
(acc, { schemaVersion, schemaType }) => {
if (!acc[schemaType]) {
acc[schemaType] = schemaVersion
} else {
if (acc[schemaType] < schemaVersion) {
acc[schemaType] = schemaVersion
}
}
return acc
},
{}
)

// types/schema/index.d.ts
const jsonSchemaType = `
${schemas
.map(
Expand All @@ -83,21 +99,30 @@ schemaType?: string;
type?: string;
schemaVersion?: number;
}
export type MapeoRecord = (${schemas
export type JSONSchema = (${schemas
.map(
/** @param {Object} schema */
({ schemaVersion, schemaType }) => {
return `${formatSchemaType(schemaType)}_${schemaVersion}`
}
({ schemaVersion, schemaType }) =>
`${formatSchemaType(schemaType)}_${schemaVersion}`
)
.join(' | ')}) & base
`
${schemas
.map(({ schemaType, schemaVersion }) => {
const as =
latestSchemaVersions[schemaType] !== schemaVersion
? `as ${formatSchemaType(schemaType)}_${schemaVersion}`
: ''
return `export { ${formatSchemaType(
schemaType
)} ${as} } from './${schemaType}/v${latestSchemaVersions[schemaType]}'`
})
.join('\n')}`
fs.writeFileSync(
path.join(__dirname, '../types/schema/index.d.ts'),
jsonSchemaType
)

// generate index.js for protobuf schemas and index.d.ts
// types/proto/index.d.ts and types/proto/index.js
const protobufFiles = glob.sync('../types/proto/*/*.ts', { cwd: 'scripts' })
const obj = protobufFiles
.filter((f) => !f.match(/.d.ts/))
Expand All @@ -116,7 +141,18 @@ const union = obj
({ schemaType, schemaVersion }) =>
`${formatSchemaType(schemaType)}_${schemaVersion.replace('v', '')}`
)
.join(' & ')
.join(' | ')

const individualExports = schemas
.map(
({ schemaType, schemaVersion }) =>
`export { ${formatSchemaType(schemaType)}_${schemaVersion} ${
latestSchemaVersions[schemaType] === schemaVersion
? `as ${formatSchemaType(schemaType)}`
: ''
}} from './${schemaType}/v${schemaVersion}'`
)
.join('\n')

obj.forEach(({ schemaType, schemaVersion }) => {
const linejs = `export { ${formatSchemaType(
Expand All @@ -143,5 +179,13 @@ fs.writeFileSync(
fs.writeFileSync(
path.join(__dirname, '../types/proto/index.d.ts'),
`${linesdts.join('\n')}
export type ProtobufSchemas = ${union}`
export type ProtobufSchema = ${union}
${individualExports}`
)

// types/index.d.ts
fs.writeFileSync(
path.join(__dirname, '../types/index.d.ts'),
`export { ProtobufSchema } from './proto'
export { JSONSchema } from './schema'`
)

0 comments on commit a3f79e0

Please sign in to comment.