From 1aa2c7a680a2b15849d96192d69eae996098e7c1 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Sun, 9 Mar 2025 09:44:51 -0700 Subject: [PATCH 01/11] Upgrate to basketry alpha --- package-lock.json | 42 ++-- package.json | 2 +- src/array-parameter-length.ts | 9 +- src/casing.ts | 79 +++--- src/enum-pluralization.ts | 5 +- src/http-delete-status.ts | 7 +- src/http-get-status.ts | 7 +- src/http-no-content-status.ts | 18 +- src/http-patch-status.ts | 7 +- src/http-post-status.ts | 7 +- src/http-put-status.ts | 7 +- src/method-description.ts | 5 +- src/offset-pagination.test.ts | 201 +++++++-------- src/offset-pagination.ts | 15 +- src/parameter-description.ts | 5 +- src/parameter-pluralization.ts | 14 +- src/property-description.ts | 5 +- src/property-pluralization.ts | 14 +- src/relay-pagination.test.ts | 442 +++++++++++---------------------- src/relay-pagination.ts | 45 ++-- src/response-envelope.ts | 11 +- src/string-id.ts | 10 +- src/test-utils.ts | 118 ++++++--- src/type-description.ts | 5 +- src/utils.ts | 18 +- 25 files changed, 513 insertions(+), 585 deletions(-) diff --git a/package-lock.json b/package-lock.json index a516b35..d8e7ff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.6", "license": "MIT", "dependencies": { - "basketry": "^0.1.4", + "basketry": "^0.2.0-alpha.7", "case": "^1.6.3", "pluralize": "^8.0.0" }, @@ -1540,7 +1540,8 @@ "node_modules/@types/node": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", - "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", + "dev": true }, "node_modules/@types/pluralize": { "version": "0.0.29", @@ -2165,9 +2166,9 @@ "dev": true }, "node_modules/basketry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.1.4.tgz", - "integrity": "sha512-BPRTeWSTa0wRnnVum9cOk4iHABv/KYPALTxBLEXB2TfMgx26AfP3ytf2yXVpa40bNHJOe8OPNaqJe1IbASI/jw==", + "version": "0.2.0-alpha.7", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.7.tgz", + "integrity": "sha512-AgVfWjtQSScMi54C1LR/Cn5IoJNDLi9uUK2yURPo73hP+2ubGh03stp82U+8A/zUhI3+valuXKDfUhMCMOx4tw==", "dependencies": { "ajv": "^8.11.0", "case": "^1.6.3", @@ -7812,6 +7813,7 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9350,7 +9352,8 @@ "@types/node": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", - "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", + "dev": true }, "@types/pluralize": { "version": "0.0.29", @@ -9535,8 +9538,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -9782,9 +9784,9 @@ "dev": true }, "basketry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.1.4.tgz", - "integrity": "sha512-BPRTeWSTa0wRnnVum9cOk4iHABv/KYPALTxBLEXB2TfMgx26AfP3ytf2yXVpa40bNHJOe8OPNaqJe1IbASI/jw==", + "version": "0.2.0-alpha.7", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.7.tgz", + "integrity": "sha512-AgVfWjtQSScMi54C1LR/Cn5IoJNDLi9uUK2yURPo73hP+2ubGh03stp82U+8A/zUhI3+valuXKDfUhMCMOx4tw==", "requires": { "ajv": "^8.11.0", "case": "^1.6.3", @@ -10537,8 +10539,7 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.6", @@ -12140,8 +12141,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "27.5.1", @@ -13962,7 +13962,8 @@ "typescript": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true }, "unbox-primitive": { "version": "1.0.1", @@ -14195,11 +14196,10 @@ } }, "ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "requires": {} + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index 61ec73e..0448748 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^4.6.4" }, "dependencies": { - "basketry": "^0.1.4", + "basketry": "^0.2.0-alpha.7", "case": "^1.6.3", "pluralize": "^8.0.0" } diff --git a/src/array-parameter-length.ts b/src/array-parameter-length.ts index b884aa5..541b594 100644 --- a/src/array-parameter-length.ts +++ b/src/array-parameter-length.ts @@ -4,15 +4,16 @@ import { parseSeverity } from './utils'; const arrayParameterLengthRule = parameterRule( ({ service, method, parameter, options }) => { if ( - parameter.isArray && - !parameter.rules.find((rule) => rule.id === 'array-max-items') + parameter.value.isArray && + !parameter.value.rules.find((rule) => rule.id === 'ArrayMaxItems') ) { + const { range, sourceIndex } = decodeRange(parameter.name.loc); return { code: 'basketry/array-parameter-length', message: `Parameter "${parameter.name.value}" (method "${method.name.value}") is an array and must define a max array length.`, - range: decodeRange(parameter.name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#array-parameter-length', }; } diff --git a/src/casing.ts b/src/casing.ts index 63dc8a7..9de2e9a 100644 --- a/src/casing.ts +++ b/src/casing.ts @@ -1,7 +1,7 @@ import { allEnums, - allEnumValues, - allHttpPaths, + allEnumMembers, + allHttpRoutes, allMethods, allParameters, allProperties, @@ -24,12 +24,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.enum); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/enum-casing', message: `Enum name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -37,16 +38,17 @@ const casingRule: Rule = (service, options) => { } if (options?.enumValue) { - for (const { value } of allEnumValues(service, options)) { + for (const { member } of allEnumMembers(service, options)) { const casing = parseCasing(options?.enumValue); - const correct = applyCasing(value.content.value, casing); - if (value.content.value !== correct) { + const correct = applyCasing(member.content.value, casing); + if (member.content.value !== correct) { + const { range, sourceIndex } = decodeRange(member.loc); violations.push({ - code: 'basketry/enum-value-casing', - message: `Enum value "${value.content.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(value.loc), + code: 'basketry/enum-member-casing', + message: `Enum member "${member.content.value}" must be ${casing} cased: "${correct}"`, + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -55,9 +57,9 @@ const casingRule: Rule = (service, options) => { if (options?.path) { for (const { - httpPath: { path }, - } of allHttpPaths(service, options)) { - for (const segment of path.value.split('/')) { + httpRoute: { pattern }, + } of allHttpRoutes(service, options)) { + for (const segment of pattern.value.split('/')) { if ( segment.startsWith(':') || (segment.startsWith('{') && segment.endsWith('}')) @@ -67,12 +69,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.path); const correct = applyCasing(segment, casing); if (segment !== correct) { + const { range, sourceIndex } = decodeRange(pattern.loc); violations.push({ - code: 'basketry/path-casing', + code: 'basketry/route-casing', message: `Path segment "${segment}" must be ${casing} cased: "${correct}"`, - range: decodeRange(path.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -87,12 +90,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.method); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/method-casing', message: `Method name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -104,18 +108,23 @@ const casingRule: Rule = (service, options) => { parameter: { name }, httpParameter, } of allParameters(service, options)) { - if (options?.header && httpParameter?.in?.value === 'header') continue; - if (options?.query && httpParameter?.in?.value === 'query') continue; + if (options?.header && httpParameter?.location?.value === 'header') { + continue; + } + if (options?.query && httpParameter?.location?.value === 'query') { + continue; + } const casing = parseCasing(options?.parameter); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/parameter-casing', message: `Parameter name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -127,17 +136,18 @@ const casingRule: Rule = (service, options) => { parameter: { name }, httpParameter, } of allParameters(service, options)) { - if (httpParameter?.in?.value !== 'header') continue; + if (httpParameter?.location?.value !== 'header') continue; const casing = parseCasing(options?.header); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/header-casing', message: `Header name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -149,17 +159,18 @@ const casingRule: Rule = (service, options) => { parameter: { name }, httpParameter, } of allParameters(service, options)) { - if (httpParameter?.in?.value !== 'query') continue; + if (httpParameter?.location?.value !== 'query') continue; const casing = parseCasing(options?.query); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/query-casing', message: `Query parameter "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -173,12 +184,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.property); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/property-casing', message: `Property name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } @@ -211,12 +223,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.type); const correct = applyCasing(name.value, casing); if (name.value !== correct) { + const { range, sourceIndex } = decodeRange(name.loc); violations.push({ code: 'basketry/type-casing', message: `Type name "${name.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } diff --git a/src/enum-pluralization.ts b/src/enum-pluralization.ts index 058661e..a6a112d 100644 --- a/src/enum-pluralization.ts +++ b/src/enum-pluralization.ts @@ -10,12 +10,13 @@ const link = 'https://github.com/basketry/rules#pluralization'; const enumPlurlaizationRule = enumRule( ({ service, enum: { name }, options }) => { if (name.value !== singular(name.value)) { + const { range, sourceIndex } = decodeRange(name.loc); return { code, message: `Enum name should be singular: "${singular(name.value)}"`, - range: decodeRange(name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }; } diff --git a/src/http-delete-status.ts b/src/http-delete-status.ts index 3723792..f5fbd88 100644 --- a/src/http-delete-status.ts +++ b/src/http-delete-status.ts @@ -10,14 +10,17 @@ const httpDeleteStatusRule = methodRule(({ service, httpMethod, options }) => { httpMethod.verb.value === 'delete' && !allowedCodes.has(httpMethod.successCode.value) ) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-delete-status', message: `HTTP status code for DELETE method "${ httpMethod.name.value }" must be one of the following: ${Array.from(allowedCodes).join(', ')}.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/http-get-status.ts b/src/http-get-status.ts index 98da09f..8b6c05c 100644 --- a/src/http-get-status.ts +++ b/src/http-get-status.ts @@ -10,14 +10,17 @@ const httpGetStatusRule = methodRule(({ service, httpMethod, options }) => { httpMethod.verb.value === 'get' && !allowedCodes.has(httpMethod.successCode.value) ) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-get-status', message: `HTTP status code for GET method "${ httpMethod.name.value }" must be one of the following: ${Array.from(allowedCodes).join(', ')}.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/http-no-content-status.ts b/src/http-no-content-status.ts index 5a7e158..7150dbb 100644 --- a/src/http-no-content-status.ts +++ b/src/http-no-content-status.ts @@ -5,21 +5,27 @@ const httpNoContentStatusRule = methodRule( ({ service, httpMethod, method, options }) => { if (!httpMethod) return; - if (!method.returnType && httpMethod.successCode.value !== 204) { + if (!method.returns && httpMethod.successCode.value !== 204) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-no-content-status', message: `Method "${httpMethod.name.value}" does not have a return type and must return an HTTP status code of 204.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], }; - } else if (method.returnType && httpMethod.successCode.value === 204) { + } else if (method.returns && httpMethod.successCode.value === 204) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-no-content-status', message: `Method "${httpMethod.name.value}" has a return type and must not return an HTTP status code of 204.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/http-patch-status.ts b/src/http-patch-status.ts index f1b4ee7..c4b884a 100644 --- a/src/http-patch-status.ts +++ b/src/http-patch-status.ts @@ -10,14 +10,17 @@ const httpPatchStatusRule = methodRule(({ service, httpMethod, options }) => { httpMethod.verb.value === 'patch' && !allowedCodes.has(httpMethod.successCode.value) ) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-patch-status', message: `HTTP status code for PATCH method "${ httpMethod.name.value }" must be one of the following: ${Array.from(allowedCodes).join(', ')}.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/http-post-status.ts b/src/http-post-status.ts index 87edcdd..80c9c76 100644 --- a/src/http-post-status.ts +++ b/src/http-post-status.ts @@ -10,14 +10,17 @@ const httpPostStatusRule = methodRule(({ service, httpMethod, options }) => { httpMethod.verb.value === 'post' && !allowedCodes.has(httpMethod.successCode.value) ) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-post-status', message: `HTTP status code for POST method "${ httpMethod.name.value }" must be one of the following: ${Array.from(allowedCodes).join(', ')}.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/http-put-status.ts b/src/http-put-status.ts index 1e50b48..b1224cd 100644 --- a/src/http-put-status.ts +++ b/src/http-put-status.ts @@ -10,14 +10,17 @@ const httpPutStatusRule = methodRule(({ service, httpMethod, options }) => { httpMethod.verb.value === 'put' && !allowedCodes.has(httpMethod.successCode.value) ) { + const { range, sourceIndex } = decodeRange( + httpMethod.successCode.loc || httpMethod.loc, + ); return { code: 'basketry/http-put-status', message: `HTTP status code for PUT method "${ httpMethod.name.value }" must be one of the following: ${Array.from(allowedCodes).join(', ')}.`, - range: decodeRange(httpMethod.successCode.loc || httpMethod.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#http-status-codes', }; } diff --git a/src/method-description.ts b/src/method-description.ts index 005344c..713c5f4 100644 --- a/src/method-description.ts +++ b/src/method-description.ts @@ -3,12 +3,13 @@ import { parseSeverity } from './utils'; const methodDescriptionRule = methodRule(({ service, method, options }) => { if (!method.description) { + const { range, sourceIndex } = decodeRange(method.loc); return { code: 'basketry/method-description', message: `Method "${method.name.value}" is required to have a description.`, - range: decodeRange(method.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#descriptions', }; } diff --git a/src/offset-pagination.test.ts b/src/offset-pagination.test.ts index 7be0387..cf7b87a 100644 --- a/src/offset-pagination.test.ts +++ b/src/offset-pagination.test.ts @@ -2,7 +2,7 @@ import { Parameter, Service, Violation } from 'basketry'; import * as build from './test-utils'; import offsetPaginationRule from './offset-pagination'; -const name = { value: 'someMethod' }; +const name = build.stringLiteral('someMethod'); describe('basketry/offset-pagination', () => { it('returns an empty array on an empty service', () => { @@ -17,31 +17,29 @@ describe('basketry/offset-pagination', () => { }); describe('when the return type is a non-envelope object', () => { - const returnType = build.returnType({ - typeName: { value: 'widget' }, - isArray: false, - isPrimitive: false, + const returns = build.returnValue({ + value: build.complexValue({ + typeName: build.stringLiteral('widget'), + }), }); const type = build.type({ - properties: [build.property({ name: { value: 'id' } })], + properties: [build.property({ name: build.stringLiteral('id') })], }); it('returns an empty array if paging parameters are not supplied', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [type], }); @@ -55,31 +53,30 @@ describe('basketry/offset-pagination', () => { }); describe('when the return type is an array', () => { - const returnType = build.returnType({ - typeName: { value: 'widget' }, - isArray: true, - isPrimitive: false, + const returns = build.returnValue({ + value: build.complexValue({ + typeName: build.stringLiteral('widget'), + isArray: build.trueLiteral(true), + }), }); const type = build.type({ - properties: [build.property({ name: { value: 'id' } })], + properties: [build.property({ name: build.stringLiteral('id') })], }); it('returns an empty array if paging parameters are supplied', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: paginationParams(), - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [type], }); @@ -95,18 +92,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [type], }); @@ -120,29 +115,27 @@ describe('basketry/offset-pagination', () => { }); describe('when the return type is an array envelope', () => { - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); const envelope = build.envelope({ isArray: true }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns an empty array if paging parameters are supplied', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: paginationParams(), - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -158,18 +151,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -183,29 +174,27 @@ describe('basketry/offset-pagination', () => { }); describe('when the return type is a non-array envelope', () => { - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); const envelope = build.envelope({ isArray: false }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns an empty array if paging parameters are not supplied', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -223,31 +212,27 @@ describe('basketry/offset-pagination', () => { allow: [name.value], }; - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); - const envelope = build.envelope({ - isArray: true, + const envelope = build.envelope({ isArray: true }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), }); it('returns a violation if an unpaged method is in the allow list', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -263,18 +248,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: paginationParams(), - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -290,18 +273,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -321,31 +302,27 @@ describe('basketry/offset-pagination', () => { deny: [name.value], }; - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); - const envelope = build.envelope({ - isArray: true, + const envelope = build.envelope({ isArray: true }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), }); it('returns an empty array if an unpaged method is in the deny list', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -361,18 +338,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: paginationParams(), - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -388,18 +363,16 @@ describe('basketry/offset-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -417,14 +390,16 @@ describe('basketry/offset-pagination', () => { const paginationParams = (): Parameter[] => [ build.parameter({ - name: { value: 'offset' }, - typeName: { value: 'integer' }, - isArray: false, + name: build.stringLiteral('offset'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('integer'), + }), }), build.parameter({ - name: { value: 'limit' }, - typeName: { value: 'integer' }, - isArray: false, + name: build.stringLiteral('limit'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('integer'), + }), }), ]; diff --git a/src/offset-pagination.ts b/src/offset-pagination.ts index 01ddebf..07019f1 100644 --- a/src/offset-pagination.ts +++ b/src/offset-pagination.ts @@ -20,28 +20,29 @@ const offsetPaginationRule = methodRule( .includes(httpMethod.verb.value)); if (!allow) return; - if (!isArrayPayload(service, options, method.returnType)) return; + if (!isArrayPayload(service, options, method.returns)) return; const offset = method.parameters.find( (p) => snake(p.name.value) === 'offset' && - p.typeName.value === 'integer' && - !isRequired(p), + p.value.typeName.value === 'integer' && + !isRequired(p.value), ); const limit = method.parameters.find( (p) => snake(p.name.value) === 'limit' && - p.typeName.value === 'integer' && - !isRequired(p), + p.value.typeName.value === 'integer' && + !isRequired(p.value), ); if (!offset || !limit) { + const { range, sourceIndex } = decodeRange(method.loc); return { code: 'basketry/offset-pagination', message: `Method "${method.name.value}" must define optional integer offset and limit parameters.`, - range: decodeRange(method.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#pagination', }; } diff --git a/src/parameter-description.ts b/src/parameter-description.ts index 1a90e78..3db61ca 100644 --- a/src/parameter-description.ts +++ b/src/parameter-description.ts @@ -4,12 +4,13 @@ import { parseSeverity } from './utils'; const parameterDescriptionRule = parameterRule( ({ service, parameter, options }) => { if (!parameter.description) { + const { range, sourceIndex } = decodeRange(parameter.loc); return { code: 'basketry/parameter-description', message: `Parameter "${parameter.name.value}" is required to have a description.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#descriptions', }; } diff --git a/src/parameter-pluralization.ts b/src/parameter-pluralization.ts index ae20474..7379e7d 100644 --- a/src/parameter-pluralization.ts +++ b/src/parameter-pluralization.ts @@ -10,23 +10,25 @@ const link = 'https://github.com/basketry/rules#pluralization'; const parameterPlurlaizationRule = parameterRule( ({ service, method, parameter, options }) => { if ( - parameter.isArray && + parameter.value.isArray && parameter.name.value !== plural(parameter.name.value) ) { + const { range, sourceIndex } = decodeRange(parameter.loc); return { code, message: `Parameter "${parameter.name.value}" (method "${ method.name.value }") is an array and must be named "${plural(parameter.name.value)}"`, - range: decodeRange(parameter.name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }; } else if ( - !parameter.isArray && + !parameter.value.isArray && parameter.name.value !== singular(parameter.name.value) ) { + const { range, sourceIndex } = decodeRange(parameter.loc); return { code, message: `Parameter "${parameter.name.value}" (method "${ @@ -34,9 +36,9 @@ const parameterPlurlaizationRule = parameterRule( }") is not an array and must be named "${singular( parameter.name.value, )}"`, - range: decodeRange(parameter.name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }; } diff --git a/src/property-description.ts b/src/property-description.ts index 67dc394..5b2bc84 100644 --- a/src/property-description.ts +++ b/src/property-description.ts @@ -4,12 +4,13 @@ import { parseSeverity } from './utils'; const propertyDescriptionRule = propertyRule( ({ service, property, options }) => { if (!property.description) { + const { range, sourceIndex } = decodeRange(property.loc); return { code: 'basketry/property-description', message: `Property "${property.name.value}" is required to have a description.`, - range: decodeRange(property.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#descriptions', }; } diff --git a/src/property-pluralization.ts b/src/property-pluralization.ts index 15b54af..1bbff7d 100644 --- a/src/property-pluralization.ts +++ b/src/property-pluralization.ts @@ -16,23 +16,25 @@ const link = 'https://github.com/basketry/rules#pluralization'; const propertyPlurlaizationRule = propertyRule( ({ service, type, property, options }) => { if ( - property.isArray && + property.value.isArray && property.name.value !== plural(property.name.value) ) { + const { range, sourceIndex } = decodeRange(property.loc); return { code, message: `Parameter "${property.name.value}" (type "${ type.name.value }") is an array and must be named "${plural(property.name.value)}"`, - range: decodeRange(property.name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }; } else if ( - !property.isArray && + !property.value.isArray && property.name.value !== singular(property.name.value) ) { + const { range, sourceIndex } = decodeRange(property.loc); return { code, message: `Parameter "${property.name.value}" (type "${ @@ -40,9 +42,9 @@ const propertyPlurlaizationRule = propertyRule( }") is not an array and must be named "${singular( property.name.value, )}"`, - range: decodeRange(property.name.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }; } diff --git a/src/relay-pagination.test.ts b/src/relay-pagination.test.ts index 0bb3ab5..67189ba 100644 --- a/src/relay-pagination.test.ts +++ b/src/relay-pagination.test.ts @@ -1,8 +1,14 @@ -import { Parameter, Service, Violation } from 'basketry'; +import { + Interface, + Parameter, + ReturnValue, + Service, + Violation, +} from 'basketry'; import * as build from './test-utils'; import relayPaginationRule from './relay-pagination'; -const name = { value: 'someMethod' }; +const name = build.stringLiteral('someMethod'); describe('basketry/relay-pagination', () => { it('returns an empty array on an empty service', () => { @@ -17,32 +23,19 @@ describe('basketry/relay-pagination', () => { }); describe('when the return type is a non-envelope object', () => { - const returnType = build.returnType({ - typeName: { value: 'widget' }, - isArray: false, - isPrimitive: false, + const returns = build.returnValue({ + value: build.complexValue({ + typeName: build.stringLiteral('widget'), + }), }); const type = build.type({ - properties: [build.property({ name: { value: 'id' } })], + properties: [build.property({ name: build.stringLiteral('id') })], }); it('returns an empty array if paging parameters are not supplied', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], + interfaces: [withoutPagination(returns)], types: [type], }); @@ -55,32 +48,20 @@ describe('basketry/relay-pagination', () => { }); describe('when the return type is an array', () => { - const returnType = build.returnType({ - typeName: { value: 'widget' }, - isArray: true, - isPrimitive: false, + const returns = build.returnValue({ + value: build.complexValue({ + typeName: build.stringLiteral('widget'), + isArray: build.trueLiteral(true), + }), }); const type = build.type({ - properties: [build.property({ name: { value: 'id' } })], + properties: [build.property({ name: build.stringLiteral('id') })], }); it('returns a violation even if paging parameters are supplied', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: paginationParams(), - returnType, - }), - ], - protocols: { http: [] }, - }, - ], + interfaces: [withPagination(returns)], types: [type], }); @@ -94,20 +75,7 @@ describe('basketry/relay-pagination', () => { it('returns a violation if paging parameters are not supplied', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], + interfaces: [withoutPagination(returns)], types: [type], }); @@ -120,65 +88,28 @@ describe('basketry/relay-pagination', () => { }); describe('when the return type is an array envelope', () => { - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); - const pageInfo = build.type({ - name: { value: 'pageInfo' }, - properties: [ - build.property({ - name: { value: 'hasPreviousPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'hasNextPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'startCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'endCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - ], - }); const envelope = build.envelope({ isArray: true, extraProperties: [ build.property({ - name: { value: 'pageInfo' }, - typeName: { value: 'pageInfo' }, - isPrimitive: false, + name: build.stringLiteral('pageInfo'), + value: build.complexValue({ + typeName: pageInfo().name, + }), }), ], }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns an empty array if paging parameters are supplied and page info is returned', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: paginationParams(), - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -192,18 +123,16 @@ describe('basketry/relay-pagination', () => { // ARRANGE const ir: Service = build.service({ interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, + build.int({ + name: build.stringLiteral('interface'), methods: [ build.method({ name, parameters: [], - returnType, + returns, }), ], - protocols: { http: [] }, - }, + }), ], types: [envelope], }); @@ -217,30 +146,17 @@ describe('basketry/relay-pagination', () => { }); describe('when the return type is a non-array envelope', () => { - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); const envelope = build.envelope({ isArray: false }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns an empty array if paging parameters are not supplied', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], + interfaces: [withoutPagination(returns)], types: [envelope], }); @@ -256,66 +172,28 @@ describe('basketry/relay-pagination', () => { const options = { allow: [name.value], }; - - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); - const pageInfo = build.type({ - name: { value: 'pageInfo' }, - properties: [ - build.property({ - name: { value: 'hasPreviousPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'hasNextPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'startCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'endCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - ], - }); const envelope = build.envelope({ isArray: true, extraProperties: [ build.property({ - name: { value: 'pageInfo' }, - typeName: { value: 'pageInfo' }, - isPrimitive: false, + name: build.stringLiteral('pageInfo'), + value: build.complexValue({ + typeName: pageInfo().name, + }), }), ], }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns a violation if an unpaged method is in the allow list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withoutPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -328,21 +206,8 @@ describe('basketry/relay-pagination', () => { it('returns an empty array if a paged method is in the allow list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: paginationParams(), - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -355,21 +220,8 @@ describe('basketry/relay-pagination', () => { it('returns an empty array if an unpaged method is not in the allow list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withoutPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -386,66 +238,28 @@ describe('basketry/relay-pagination', () => { const options = { deny: [name.value], }; - - const returnType = build.returnType({ - typeName: { value: 'envelope' }, - isArray: false, - isPrimitive: false, - }); - const pageInfo = build.type({ - name: { value: 'pageInfo' }, - properties: [ - build.property({ - name: { value: 'hasPreviousPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'hasNextPage' }, - typeName: { value: 'boolean' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'startCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - build.property({ - name: { value: 'endCursor' }, - typeName: { value: 'string' }, - isPrimitive: true, - }), - ], - }); const envelope = build.envelope({ isArray: true, extraProperties: [ build.property({ - name: { value: 'pageInfo' }, - typeName: { value: 'pageInfo' }, - isPrimitive: false, + name: build.stringLiteral('pageInfo'), + value: build.complexValue({ + typeName: pageInfo().name, + }), }), ], }); + const returns = build.returnValue({ + value: build.complexValue({ + typeName: envelope.name, + }), + }); it('returns an empty array if an unpaged method is in the deny list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withoutPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -458,21 +272,8 @@ describe('basketry/relay-pagination', () => { it('returns an empty array if a paged method is in the deny list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: paginationParams(), - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -485,21 +286,8 @@ describe('basketry/relay-pagination', () => { it('returns a violation if an unpaged method is not in the deny list', () => { // ARRANGE const ir: Service = build.service({ - interfaces: [ - { - kind: 'Interface', - name: { value: 'interface' }, - methods: [ - build.method({ - name, - parameters: [], - returnType, - }), - ], - protocols: { http: [] }, - }, - ], - types: [envelope, pageInfo], + interfaces: [withoutPagination(returns)], + types: [envelope, pageInfo()], }); // ACT @@ -513,29 +301,89 @@ describe('basketry/relay-pagination', () => { }); }); +const withPagination = (returns: ReturnValue): Interface => + build.int({ + name: build.stringLiteral('interface'), + methods: [ + build.method({ + name, + parameters: paginationParams(), + returns, + }), + ], + }); + +const withoutPagination = (returns: ReturnValue): Interface => + build.int({ + name: build.stringLiteral('interface'), + methods: [ + build.method({ + name, + parameters: [], + returns, + }), + ], + }); + const paginationParams = (): Parameter[] => [ build.parameter({ - name: { value: 'first' }, - typeName: { value: 'integer' }, - isArray: false, + name: build.stringLiteral('first'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('integer'), + }), }), build.parameter({ - name: { value: 'after' }, - typeName: { value: 'string' }, - isArray: false, + name: build.stringLiteral('after'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('string'), + }), }), build.parameter({ - name: { value: 'last' }, - typeName: { value: 'integer' }, - isArray: false, + name: build.stringLiteral('last'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('integer'), + }), }), build.parameter({ - name: { value: 'before' }, - typeName: { value: 'string' }, - isArray: false, + name: build.stringLiteral('before'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('string'), + }), }), ]; +function pageInfo() { + return build.type({ + name: build.stringLiteral('pageInfo'), + properties: [ + build.property({ + name: build.stringLiteral('hasPreviousPage'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('boolean'), + }), + }), + build.property({ + name: build.stringLiteral('hasNextPage'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('boolean'), + }), + }), + build.property({ + name: build.stringLiteral('startCursor'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('string'), + }), + }), + build.property({ + name: build.stringLiteral('endCursor'), + value: build.primitiveValue({ + typeName: build.primitiveLiteral('string'), + }), + }), + ], + }); +} + const violation = (): Violation => ({ code: 'basketry/relay-pagination', message: `Method "${name.value}" must define optional relay pagination parameters and return a "page info" object.`, diff --git a/src/relay-pagination.ts b/src/relay-pagination.ts index ee2d0c2..68b6dba 100644 --- a/src/relay-pagination.ts +++ b/src/relay-pagination.ts @@ -26,82 +26,83 @@ const relayPaginationRule = methodRule( .includes(httpMethod.verb.value)); if (!allow) return; - if (!isArrayPayload(service, options, method.returnType)) return; + if (!isArrayPayload(service, options, method.returns)) return; const first = () => method.parameters.find( (p) => snake(p.name.value) === 'first' && - p.typeName.value === 'integer' && - !isRequired(p), + p.value.typeName.value === 'integer' && + !isRequired(p.value), ); const after = () => method.parameters.find( (p) => snake(p.name.value) === 'after' && - p.typeName.value === 'string' && - !isRequired(p), + p.value.typeName.value === 'string' && + !isRequired(p.value), ); const last = () => method.parameters.find( (p) => snake(p.name.value) === 'last' && - p.typeName.value === 'integer' && - !isRequired(p), + p.value.typeName.value === 'integer' && + !isRequired(p.value), ); const before = () => method.parameters.find( (p) => snake(p.name.value) === 'before' && - p.typeName.value === 'string' && - !isRequired(p), + p.value.typeName.value === 'string' && + !isRequired(p.value), ); const pageInfo = () => - getTypeByName(service, method.returnType?.typeName.value) - ?.properties.filter((prop) => !prop.isPrimitive) - .map((prop) => getTypeByName(service, prop.typeName.value)) + getTypeByName(service, method.returns?.value.typeName.value) + ?.properties.filter((prop) => prop.value.kind === 'ComplexValue') + .map((prop) => getTypeByName(service, prop.value.typeName.value)) .filter((type): type is Type => !!type) .find((type) => { const hasPreviousPage = type.properties.find( (prop) => camel(prop.name.value) === 'hasPreviousPage' && - prop.isPrimitive && - prop.typeName.value === 'boolean', + prop.value.kind === 'PrimitiveValue' && + prop.value.typeName.value === 'boolean', ); if (!hasPreviousPage) return false; const hasNextPage = type.properties.find( (prop) => camel(prop.name.value) === 'hasNextPage' && - prop.isPrimitive && - prop.typeName.value === 'boolean', + prop.value.kind === 'PrimitiveValue' && + prop.value.typeName.value === 'boolean', ); if (!hasNextPage) return false; const startCursor = type.properties.find( (prop) => camel(prop.name.value) === 'startCursor' && - prop.isPrimitive && - prop.typeName.value === 'string', + prop.value.kind === 'PrimitiveValue' && + prop.value.typeName.value === 'string', ); if (!startCursor) return false; const endCursor = type.properties.find( (prop) => camel(prop.name.value) === 'endCursor' && - prop.isPrimitive && - prop.typeName.value === 'string', + prop.value.kind === 'PrimitiveValue' && + prop.value.typeName.value === 'string', ); return !!endCursor; }); if (!first() || !after() || !last() || !before() || !pageInfo()) { + const { range, sourceIndex } = decodeRange(method.loc); return { code: 'basketry/relay-pagination', message: `Method "${method.name.value}" must define optional relay pagination parameters and return a "page info" object.`, - range: decodeRange(method.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#pagination', }; } diff --git a/src/response-envelope.ts b/src/response-envelope.ts index 3630110..e45a792 100644 --- a/src/response-envelope.ts +++ b/src/response-envelope.ts @@ -5,9 +5,9 @@ import { parseSeverity } from './utils'; const allowed = new Set(['value', 'values', 'data']); const responseEnvelopeRule = methodRule(({ method, service, options }) => { - if (!method.returnType) return; + if (!method.returns) return; const type = service.types.find( - (t) => t.name.value === method.returnType?.typeName.value, + (t) => t.name.value === method.returns?.value.typeName.value, ); const errors = type?.properties.find((p) => snake(p.name.value) === 'errors'); @@ -16,7 +16,8 @@ const responseEnvelopeRule = methodRule(({ method, service, options }) => { parseAllowed(options?.payload).has(snake(p.name.value)), ); - if (!errors?.isArray || !payload) { + if (!errors?.value.isArray || !payload) { + const { range, sourceIndex } = decodeRange(method.returns.loc); return { code: 'basketry/response-envelope', message: `Method "${ @@ -24,9 +25,9 @@ const responseEnvelopeRule = methodRule(({ method, service, options }) => { }" must return an envelope with at least an errors array and payload property with one of the following names: ${getAllowed( options?.payload, ).join(', ')}.`, - range: decodeRange(method.returnType.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#response-envelopes', }; } diff --git a/src/string-id.ts b/src/string-id.ts index 558fb3a..7c28aad 100644 --- a/src/string-id.ts +++ b/src/string-id.ts @@ -2,13 +2,17 @@ import { decodeRange, propertyRule } from 'basketry'; import { parseSeverity } from './utils'; const stringIdRule = propertyRule(({ service, property, options }) => { - if (property.name.value === 'id' && property.typeName.value !== 'string') { + if ( + property.name.value.toLowerCase() === 'id' && + property.value.typeName.value !== 'string' + ) { + const { range, sourceIndex } = decodeRange(property.loc); return { code: 'basketry/string-id', message: 'Type IDs must be of type `string`', - range: decodeRange(property.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#string-ids', }; } diff --git a/src/test-utils.ts b/src/test-utils.ts index 14674be..cefdfbe 100644 --- a/src/test-utils.ts +++ b/src/test-utils.ts @@ -1,12 +1,37 @@ import { + ComplexValue, + IntegerLiteral, + Interface, + MemberValue, Method, Parameter, + Primitive, + PrimitiveLiteral, + PrimitiveValue, Property, - ReturnType, + ReturnValue, Service, + StringLiteral, + TrueLiteral, Type, } from 'basketry'; +export function stringLiteral(value: string): StringLiteral { + return { kind: 'StringLiteral', value }; +} + +export function integerLiteral(value: number): IntegerLiteral { + return { kind: 'IntegerLiteral', value }; +} + +export function primitiveLiteral(value: Primitive): PrimitiveLiteral { + return { kind: 'PrimitiveLiteral', value }; +} + +export function trueLiteral(value: boolean): TrueLiteral | undefined { + return value ? { kind: 'TrueLiteral', value: true } : undefined; +} + export function envelope({ isArray, payload = 'data', @@ -17,17 +42,21 @@ export function envelope({ extraProperties?: Property[]; }): Type { return type({ - name: { value: 'envelope' }, + name: stringLiteral('envelope'), properties: [ property({ - name: { value: 'errors' }, - isArray: true, - isPrimitive: false, + name: stringLiteral('errors'), + value: complexValue({ + typeName: stringLiteral('error'), + isArray: trueLiteral(true), + }), }), property({ - name: { value: payload }, - isArray, - isPrimitive: false, + name: stringLiteral(payload), + value: complexValue({ + typeName: stringLiteral('widget'), + isArray: trueLiteral(isArray), + }), }), ...(extraProperties || []), ], @@ -37,19 +66,28 @@ export function envelope({ export function method(defaults: Partial = {}): Method { return { kind: 'Method', - name: { value: 'method' }, + name: stringLiteral('method'), security: [], - returnType: undefined, + returns: undefined, parameters: [], loc: '1;1;0', ...defaults, }; } +export function int(defaults: Partial = {}): Interface { + return { + kind: 'Interface', + name: stringLiteral('interface'), + methods: [], + ...defaults, + }; +} + export function type(defaults: Partial = {}): Type { return { kind: 'Type', - name: { value: 'type' }, + name: stringLiteral('type'), properties: [], rules: [], loc: '1;1;0', @@ -57,48 +95,64 @@ export function type(defaults: Partial = {}): Type { }; } -export function returnType(defaults: Partial = {}): ReturnType { +export function primitiveValue( + defaults: Partial = {}, +): PrimitiveValue { return { - typeName: { value: 'string' }, - isArray: false, - isPrimitive: true, + kind: 'PrimitiveValue', + typeName: primitiveLiteral('string'), rules: [], + ...defaults, + }; +} + +export function complexValue( + defaults: Partial = {}, +): ComplexValue { + return { + kind: 'ComplexValue', + typeName: stringLiteral('type'), + rules: [], + ...defaults, + }; +} + +export function returnValue(defaults: Partial = {}): ReturnValue { + return { + kind: 'ReturnValue', + value: primitiveValue(), loc: '1;1;0', ...defaults, - } as ReturnType; + }; } export function property(defaults: Partial = {}): Property { return { - name: { value: 'prop' }, - isArray: false, - isPrimitive: true, - rules: [], - typeName: { value: 'string' }, + kind: 'Property', + name: stringLiteral('prop'), + value: primitiveValue(), loc: '1;1;0', ...defaults, - } as Property; + }; } export function parameter(defaults: Partial = {}): Parameter { return { - name: { value: 'param' }, - isArray: false, - isPrimitive: true, - rules: [], - typeName: { value: 'string' }, + kind: 'Parameter', + name: stringLiteral('param'), + value: primitiveValue(), loc: '1;1;0', ...defaults, - } as Parameter; + }; } export function service(defaults: Partial = {}): Service { return { kind: 'Service', - basketry: '1.1-rc', - title: { value: 'test' }, - majorVersion: { value: 1 }, - sourcePath: 'test.ext', + basketry: '0.2', + title: stringLiteral('test'), + majorVersion: { kind: 'IntegerLiteral', value: 1 }, + sourcePaths: ['test.ext'], interfaces: [], types: [], enums: [], diff --git a/src/type-description.ts b/src/type-description.ts index 836db81..f636d5b 100644 --- a/src/type-description.ts +++ b/src/type-description.ts @@ -3,12 +3,13 @@ import { parseSeverity } from './utils'; const typeDescriptionRule = typeRule(({ service, type, options }) => { if (!type.description) { + const { range, sourceIndex } = decodeRange(type.loc); return { code: 'basketry/type-description', message: `Type "${type.name.value}" is required to have a description.`, - range: decodeRange(type.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#descriptions', }; } diff --git a/src/utils.ts b/src/utils.ts index 2641914..9cb03bc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { getTypeByName, ReturnType, Service, Severity } from 'basketry'; +import { getTypeByName, ReturnValue, Service, Severity } from 'basketry'; import { camel, constant, header, kebab, pascal, snake } from 'case'; export type Casing = @@ -61,24 +61,24 @@ const allowedPayloadProps = new Set(['value', 'values', 'data']); export function isArrayPayload( service: Service, options: any, - returnType: ReturnType | undefined, + returns: ReturnValue | undefined, ): boolean { - if (!returnType) return false; + if (!returns) return false; - const type = getTypeByName(service, returnType.typeName.value); - if (!type) return returnType.isArray; + const type = getTypeByName(service, returns.value.typeName.value); + if (!type) return returns.value.isArray?.value === true; const errorProp = type.properties.find( - (prop) => snake(prop.name.value) === 'errors' && prop.isArray, + (prop) => snake(prop.name.value) === 'errors' && prop.value.isArray, ); - if (!errorProp) return returnType.isArray; + if (!errorProp) return returns.value.isArray?.value === true; const payloadProp = type.properties.find((p) => parseAllowedPayloadProps(options?.payload).has(snake(p.name.value)), ); - if (!payloadProp) return returnType.isArray; + if (!payloadProp) return returns.value.isArray?.value === true; - return payloadProp.isArray; + return payloadProp.value.isArray?.value === true; } function parseAllowedPayloadProps(input: any): Set { From 5fed8f7e6ba49bac1a6cdf73439a1823394cdafb Mon Sep 17 00:00:00 2001 From: skonves Date: Sun, 9 Mar 2025 16:54:14 +0000 Subject: [PATCH 02/11] 0.2.0-alpha.0 Co-authored-by: github-actions[bot] --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d8e7ff9..257717f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@basketry/rules", - "version": "0.1.6", + "version": "0.2.0-alpha.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@basketry/rules", - "version": "0.1.6", + "version": "0.2.0-alpha.0", "license": "MIT", "dependencies": { "basketry": "^0.2.0-alpha.7", diff --git a/package.json b/package.json index 0448748..f81523e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@basketry/rules", - "version": "0.1.6", + "version": "0.2.0-alpha.0", "description": "Common rules for building Basketry pipelines", "main": "./lib/index.js", "scripts": { From 40b777a4eda1866160fb0516b1092d5358352fe7 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Thu, 29 May 2025 07:37:19 -0700 Subject: [PATCH 03/11] Upgrade to latest alpha --- package-lock.json | 47 +++++++++++++++++++++++++---------------------- package.json | 2 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 257717f..dfac285 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.0-alpha.0", "license": "MIT", "dependencies": { - "basketry": "^0.2.0-alpha.7", + "basketry": "^0.2.0-alpha.13", "case": "^1.6.3", "pluralize": "^8.0.0" }, @@ -28,6 +28,9 @@ "rimraf": "^3.0.2", "ts-jest": "^27.1.4", "typescript": "^4.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/basketry" } }, "node_modules/@ampproject/remapping": { @@ -1540,8 +1543,7 @@ "node_modules/@types/node": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", - "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", - "dev": true + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" }, "node_modules/@types/pluralize": { "version": "0.0.29", @@ -2166,9 +2168,9 @@ "dev": true }, "node_modules/basketry": { - "version": "0.2.0-alpha.7", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.7.tgz", - "integrity": "sha512-AgVfWjtQSScMi54C1LR/Cn5IoJNDLi9uUK2yURPo73hP+2ubGh03stp82U+8A/zUhI3+valuXKDfUhMCMOx4tw==", + "version": "0.2.0-alpha.13", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.13.tgz", + "integrity": "sha512-kGL+NsVKHlf2RJTafRR7uwlq/lfWxAHXL9mLsAuHZrx9X26Q2nnxHEQ0ZlV3OV9g+v76SQ8DB0R4S1+22lOrbQ==", "dependencies": { "ajv": "^8.11.0", "case": "^1.6.3", @@ -2181,7 +2183,7 @@ "basketry": "lib/cli.js" }, "funding": { - "url": "https://github.com/basketry/basketry?sponsor=1" + "url": "https://github.com/sponsors/basketry" } }, "node_modules/basketry/node_modules/ajv": { @@ -7813,7 +7815,6 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9352,8 +9353,7 @@ "@types/node": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", - "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", - "dev": true + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" }, "@types/pluralize": { "version": "0.0.29", @@ -9538,7 +9538,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "7.2.0", @@ -9784,9 +9785,9 @@ "dev": true }, "basketry": { - "version": "0.2.0-alpha.7", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.7.tgz", - "integrity": "sha512-AgVfWjtQSScMi54C1LR/Cn5IoJNDLi9uUK2yURPo73hP+2ubGh03stp82U+8A/zUhI3+valuXKDfUhMCMOx4tw==", + "version": "0.2.0-alpha.13", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.13.tgz", + "integrity": "sha512-kGL+NsVKHlf2RJTafRR7uwlq/lfWxAHXL9mLsAuHZrx9X26Q2nnxHEQ0ZlV3OV9g+v76SQ8DB0R4S1+22lOrbQ==", "requires": { "ajv": "^8.11.0", "case": "^1.6.3", @@ -10539,7 +10540,8 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true + "dev": true, + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.6", @@ -12141,7 +12143,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "27.5.1", @@ -13962,8 +13965,7 @@ "typescript": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" }, "unbox-primitive": { "version": "1.0.1", @@ -14196,10 +14198,11 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "requires": {} }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index f81523e..0de387a 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^4.6.4" }, "dependencies": { - "basketry": "^0.2.0-alpha.7", + "basketry": "^0.2.0-alpha.13", "case": "^1.6.3", "pluralize": "^8.0.0" } From 8f5d93d7039eef864995d3bbbd8fe4db2eb54b88 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Thu, 29 May 2025 07:37:38 -0700 Subject: [PATCH 04/11] Update rules --- src/casing.ts | 5 +- src/json-api-error.ts | 108 ++++++++++++++++++++---------------- src/no-free-form-objects.ts | 17 +++--- src/no-http-delete-body.ts | 10 +++- src/no-http-get-body.ts | 10 +++- src/no-http-head-body.ts | 10 +++- src/no-http-options-body.ts | 10 +++- src/no-http-trace-body.ts | 10 +++- src/no-mixed-properties.ts | 6 +- src/object-request-body.ts | 18 +++--- src/object-response-body.ts | 20 ++++--- src/string-map-key.ts | 20 ++++--- 12 files changed, 146 insertions(+), 98 deletions(-) diff --git a/src/casing.ts b/src/casing.ts index 9de2e9a..aee782c 100644 --- a/src/casing.ts +++ b/src/casing.ts @@ -203,12 +203,13 @@ const casingRule: Rule = (service, options) => { const casing = parseCasing(options?.property); const correct = applyCasing(requiredKey.value, casing); if (requiredKey.value !== correct) { + const { range, sourceIndex } = decodeRange(requiredKey.loc); violations.push({ code: 'basketry/property-casing', message: `Property name "${requiredKey.value}" must be ${casing} cased: "${correct}"`, - range: decodeRange(requiredKey.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link, }); } diff --git a/src/json-api-error.ts b/src/json-api-error.ts index 1a64efa..4da91ab 100644 --- a/src/json-api-error.ts +++ b/src/json-api-error.ts @@ -22,12 +22,13 @@ const jsonApiErrorRule: Rule = (service, options) => { (type) => snake(type.name.value) === 'error', ); if (!error) { + const { range, sourceIndex } = decodeRange(service.loc); violations.push({ code, message: 'Service must define an `error` type.', severity, - sourcePath: service.sourcePath, - range: decodeRange(service.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); return violations; @@ -45,60 +46,66 @@ const jsonApiErrorRule: Rule = (service, options) => { ): void { const prop = getProperty(type, path); if (prop) { - if (opt?.required && !isRequired(prop)) { + if (opt?.required && !isRequired(prop.value)) { + const { range, sourceIndex } = decodeRange(prop.name.loc ?? prop.loc); violations.push({ code, message: `Property \`${path}\` must be required.`, severity, - sourcePath: service.sourcePath, - range: decodeRange(prop.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); - return; - } - - if (prop.isArray && !opt?.allowArray) { + } else if (prop.value.isArray && !opt?.allowArray) { + const { range, sourceIndex } = decodeRange( + prop.value.isArray.loc ?? prop.name.loc ?? prop.loc, + ); violations.push({ code, message: `Property \`${path}\` must not be an array.`, severity, - sourcePath: service.sourcePath, - range: decodeRange(prop.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, + link, + }); + } else { + const isString = + prop.value.kind === 'PrimitiveValue' && + prop.value.typeName.value === 'string'; + const isNumeric = + prop.value.kind === 'PrimitiveValue' && + (prop.value.typeName.value === 'double' || + prop.value.typeName.value === 'float' || + prop.value.typeName.value === 'integer' || + prop.value.typeName.value === 'long' || + prop.value.typeName.value === 'number'); + if (isString) return; + if (isNumeric && opt?.allowNumeric) return; + const isEnum = !!getEnumByName(service, prop.value.typeName.value); + if (isEnum && opt?.allowEnums) return; + + const { range, sourceIndex } = decodeRange( + prop.value.typeName.loc ?? prop.name.loc ?? prop.loc, + ); + violations.push({ + code, + message: `Property \`${path}\` must be a string${ + opt?.allowEnums ? ' or enum' : '' + }${opt?.allowNumeric ? ' or numeric type' : ''}.`, + severity, + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); - return; } - - const isString = prop.isPrimitive && prop.typeName.value === 'string'; - const isNumeric = - prop.isPrimitive && - (prop.typeName.value === 'double' || - prop.typeName.value === 'float' || - prop.typeName.value === 'integer' || - prop.typeName.value === 'long' || - prop.typeName.value === 'number'); - if (isString) return; - if (isNumeric && opt?.allowNumeric) return; - const isEnum = !!getEnumByName(service, prop.typeName.value); - if (isEnum && opt?.allowEnums) return; - - violations.push({ - code, - message: `Property \`${path}\` must be a string${ - opt?.allowEnums ? ' or enum' : '' - }${opt?.allowNumeric ? ' or numeric type' : ''}.`, - severity, - sourcePath: service.sourcePath, - range: decodeRange(prop.typeName.loc), - link, - }); } else if (opt?.required) { + const { range, sourceIndex } = decodeRange(type.name.loc ?? type.loc); violations.push({ code, message: `Property \`${path}\` must be defined.`, severity, - sourcePath: service.sourcePath, - range: decodeRange(type.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); } @@ -108,8 +115,8 @@ const jsonApiErrorRule: Rule = (service, options) => { if (!type) return undefined; return getTypeByName( service, - type?.properties.find((p) => snake(p.name.value) === snake(prop)) - ?.typeName.value, + type?.properties.find((p) => snake(p.name.value) === snake(prop))?.value + .typeName.value, ); } @@ -122,7 +129,7 @@ const jsonApiErrorRule: Rule = (service, options) => { ); if (!prop) return undefined; - currentType = getTypeByName(service, prop.typeName.value); + currentType = getTypeByName(service, prop.value.typeName.value); } return prop; } @@ -170,19 +177,22 @@ const jsonApiErrorRule: Rule = (service, options) => { function checkLink(lnk: Property | undefined): void { if (!lnk) return; - if (lnk.isPrimitive) { - if (lnk.typeName.value !== 'string') { + if (lnk.value.kind === 'PrimitiveValue') { + if (lnk.value.typeName.value !== 'string') { + const { range, sourceIndex } = decodeRange( + lnk.value.typeName.loc ?? lnk.name.loc ?? lnk.loc, + ); violations.push({ code, message: `Property \`${lnk.name.value}\` must be a string or an object.`, severity, - sourcePath: service.sourcePath, - range: decodeRange(lnk.typeName.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); } } else { - const type = getTypeByName(service, lnk.typeName.value); + const type = getTypeByName(service, lnk.value.typeName.value); if (!type) return; check(type, 'href', { required: true }); @@ -212,6 +222,8 @@ const jsonApiErrorRule: Rule = (service, options) => { // Check for non-standard properties for (const prop of type.properties) { if (!knownProperties.has(snake(prop.name.value))) { + const { range, sourceIndex } = decodeRange(prop.name.loc ?? prop.loc); + violations.push({ code, message: `Property \`${ @@ -222,8 +234,8 @@ const jsonApiErrorRule: Rule = (service, options) => { ', ', )}. Define non-standard meta-information in \`error.meta\`.`, severity, - sourcePath: service.sourcePath, - range: decodeRange(prop.name.loc), + sourcePath: service.sourcePaths[sourceIndex], + range, link, }); } diff --git a/src/no-free-form-objects.ts b/src/no-free-form-objects.ts index d74fbcf..c74aae7 100644 --- a/src/no-free-form-objects.ts +++ b/src/no-free-form-objects.ts @@ -6,20 +6,19 @@ const noFreeFormObjects = typeRule(({ service, type, options }) => { if (!mapProperties) return; if ( - mapProperties.value.isPrimitive && - mapProperties.value.typeName.value === 'untyped' + mapProperties.value.value.kind === 'PrimitiveValue' && + mapProperties.value.value.typeName.value === 'untyped' ) { + const { range, sourceIndex } = decodeRange( + mapProperties.value.loc ?? mapProperties.loc ?? type.name.loc ?? type.loc, + ); + return { code: 'basketry/no-free-form-objects', message: 'Map type must explicitly define a value schema.', - range: decodeRange( - mapProperties.value.loc ?? - mapProperties.loc ?? - type.name.loc ?? - type.loc, - ), + range, severity: parseSeverity(options?.severity, 'error'), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], }; } diff --git a/src/no-http-delete-body.ts b/src/no-http-delete-body.ts index 35cb8c1..9b25107 100644 --- a/src/no-http-delete-body.ts +++ b/src/no-http-delete-body.ts @@ -6,14 +6,18 @@ const noHttpDeleteBodyRule = parameterRule( if (!httpParameter) return; if (!httpMethod) return; if (httpMethod.verb.value !== 'delete') return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; + + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); return { code: 'basketry/no-http-delete-body', message: `HTTP DELETE method "${method.name.value}" must not define a body parameter.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#no-http-delete-body', }; }, diff --git a/src/no-http-get-body.ts b/src/no-http-get-body.ts index 2979fe3..265d774 100644 --- a/src/no-http-get-body.ts +++ b/src/no-http-get-body.ts @@ -6,14 +6,18 @@ const noHttpGetBodyRule = parameterRule( if (!httpParameter) return; if (!httpMethod) return; if (httpMethod.verb.value !== 'get') return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; + + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); return { code: 'basketry/no-http-get-body', message: `HTTP GET method "${method.name.value}" must not define a body parameter.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#no-http-get-body', }; }, diff --git a/src/no-http-head-body.ts b/src/no-http-head-body.ts index 4fd3ce2..525267b 100644 --- a/src/no-http-head-body.ts +++ b/src/no-http-head-body.ts @@ -6,14 +6,18 @@ const noHttpHeadBodyRule = parameterRule( if (!httpParameter) return; if (!httpMethod) return; if (httpMethod.verb.value !== 'head') return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; + + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); return { code: 'basketry/no-http-head-body', message: `HTTP HEAD method "${method.name.value}" must not define a body parameter.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#no-http-head-body', }; }, diff --git a/src/no-http-options-body.ts b/src/no-http-options-body.ts index dae8ab8..eb62842 100644 --- a/src/no-http-options-body.ts +++ b/src/no-http-options-body.ts @@ -6,14 +6,18 @@ const noHttpOptionsBodyRule = parameterRule( if (!httpParameter) return; if (!httpMethod) return; if (httpMethod.verb.value !== 'options') return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; + + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); return { code: 'basketry/no-http-options-body', message: `HTTP OPTIONS method "${method.name.value}" must not define a body parameter.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#no-http-options-body', }; }, diff --git a/src/no-http-trace-body.ts b/src/no-http-trace-body.ts index 1dd044d..d42c7e4 100644 --- a/src/no-http-trace-body.ts +++ b/src/no-http-trace-body.ts @@ -6,14 +6,18 @@ const noHttpTraceBodyRule = parameterRule( if (!httpParameter) return; if (!httpMethod) return; if (httpMethod.verb.value !== 'trace') return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; + + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); return { code: 'basketry/no-http-trace-body', message: `HTTP TRACE method "${method.name.value}" must not define a body parameter.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#no-http-trace-body', }; }, diff --git a/src/no-mixed-properties.ts b/src/no-mixed-properties.ts index c2cd238..03d3443 100644 --- a/src/no-mixed-properties.ts +++ b/src/no-mixed-properties.ts @@ -5,14 +5,16 @@ const noMixedProperties = typeRule(({ service, type, options }) => { const { mapProperties } = type; if (!mapProperties) return; + const { range, sourceIndex } = decodeRange(type.name.loc ?? type.loc); + if (type.properties.length) { return { code: 'basketry/no-mixed-properties', message: 'Types may not have mixed properties. Choose between defined properties or a map.', - range: decodeRange(type.name.loc ?? type.loc), + range, severity: parseSeverity(options?.severity, 'error'), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], }; } diff --git a/src/object-request-body.ts b/src/object-request-body.ts index 9bed699..c212b37 100644 --- a/src/object-request-body.ts +++ b/src/object-request-body.ts @@ -10,22 +10,26 @@ const objectRequestBodyRule = parameterRule( ({ parameter, httpParameter, service, options }) => { if (!httpParameter) return; - if (httpParameter.in.value !== 'body') return; + if (httpParameter.location.value !== 'body') return; - const type = getTypeByName(service, parameter.typeName.value); - if (type && !parameter.isArray) return; + const type = getTypeByName(service, parameter.value.typeName.value); + if (type && !parameter.value.isArray) return; - const union = getUnionByName(service, parameter.typeName.value); - if (union && union.members.every((m) => !m.isArray && !m.isPrimitive)) { + const union = getUnionByName(service, parameter.value.typeName.value); + if (union?.members.every((m) => !m.isArray && m.kind === 'ComplexValue')) { return; } + const { range, sourceIndex } = decodeRange( + parameter.name.loc ?? parameter.loc, + ); + return { code: 'basketry/object-request-body', message: `Body parameter "${parameter.name.value}" must be an object or a union of objects.`, - range: decodeRange(parameter.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#object-request-body', }; }, diff --git a/src/object-response-body.ts b/src/object-response-body.ts index 7c4987d..8ad9461 100644 --- a/src/object-response-body.ts +++ b/src/object-response-body.ts @@ -7,21 +7,25 @@ import { import { parseSeverity } from './utils'; const objectResponseBodyRule = methodRule(({ method, service, options }) => { - const returnType = method.returnType; - if (!returnType) return; + const returnValue = method.returns; + if (!returnValue) return; - const type = getTypeByName(service, returnType.typeName.value); - if (type && !returnType.isArray) return; + const type = getTypeByName(service, returnValue.value.typeName.value); + if (type && !returnValue.value.isArray) return; - const union = getUnionByName(service, returnType.typeName.value); - if (union && union.members.every((m) => !m.isArray && !m.isPrimitive)) return; + const union = getUnionByName(service, returnValue.value.typeName.value); + if (union?.members.every((m) => !m.isArray && m.kind === 'ComplexValue')) { + return; + } + + const { range, sourceIndex } = decodeRange(method.name.loc ?? method.loc); return { code: 'basketry/object-response-body', message: `Method "${method.name.value}" must return an object or a union of objects.`, - range: decodeRange(method.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], link: 'https://github.com/basketry/rules#object-response-body', }; }); diff --git a/src/string-map-key.ts b/src/string-map-key.ts index 20ecf97..3e87db9 100644 --- a/src/string-map-key.ts +++ b/src/string-map-key.ts @@ -13,26 +13,32 @@ const stringMapKeys: Rule = (service, options) => { const { mapProperties } = type; if (!mapProperties) continue; - if (mapProperties.key.isArray) { + if (mapProperties.key.value.isArray) { + const { range, sourceIndex } = decodeRange( + mapProperties.key.loc ?? mapProperties.loc ?? type.name.loc ?? type.loc, + ); violations.push({ code: 'basketry/string-map-key', message: `Map key must not be an array.`, - range: decodeRange(mapProperties.key.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], }); } if ( - !mapProperties.key.isPrimitive || - mapProperties.key.typeName.value !== 'string' + mapProperties.key.value.kind === 'ComplexValue' || + mapProperties.key.value.typeName.value !== 'string' ) { + const { range, sourceIndex } = decodeRange( + mapProperties.key.loc ?? mapProperties.loc ?? type.name.loc ?? type.loc, + ); violations.push({ code: 'basketry/string-map-key', message: `Map keys must be a string.`, - range: decodeRange(mapProperties.key.loc), + range, severity: parseSeverity(options?.severity), - sourcePath: service.sourcePath, + sourcePath: service.sourcePaths[sourceIndex], }); } } From aef7dc7480b872d0086b58a8e2d3c2993d264456 Mon Sep 17 00:00:00 2001 From: skonves Date: Thu, 29 May 2025 14:39:42 +0000 Subject: [PATCH 05/11] 0.2.0-alpha.1 Co-authored-by: github-actions[bot] --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index dfac285..f7afcd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.0", + "version": "0.2.0-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@basketry/rules", - "version": "0.2.0-alpha.0", + "version": "0.2.0-alpha.1", "license": "MIT", "dependencies": { "basketry": "^0.2.0-alpha.13", diff --git a/package.json b/package.json index 0de387a..c39e52c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.0", + "version": "0.2.0-alpha.1", "description": "Common rules for building Basketry pipelines", "main": "./lib/index.js", "scripts": { From ef9d792d9bc335e7aab3d00fdf17f637117d7e31 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Sat, 26 Jul 2025 16:24:54 -0700 Subject: [PATCH 06/11] Upgrade to latest alpha --- package-lock.json | 111 ++++++++++++++++++++-------------- package.json | 2 +- src/offset-pagination.test.ts | 2 + src/relay-pagination.test.ts | 4 ++ 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7afcd2..23cc39a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.0-alpha.1", "license": "MIT", "dependencies": { - "basketry": "^0.2.0-alpha.13", + "basketry": "^0.2.0-alpha.18", "case": "^1.6.3", "pluralize": "^8.0.0" }, @@ -533,6 +533,37 @@ "node": ">=6.9.0" } }, + "node_modules/@basketry/ir": { + "version": "0.2.0-alpha.3", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-alpha.3.tgz", + "integrity": "sha512-Ik8UH6GbI+jpOuDdZvnqFASZyicwzKsRStLVtQNvS9Q+eqbOSvJ0wzEkMYw9WmljZCl9U45uHIKDvdOTs07g4Q==", + "dependencies": { + "ajv": "^8.17.1" + }, + "funding": { + "url": "https://github.com/sponsors/basketry" + } + }, + "node_modules/@basketry/ir/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@basketry/ir/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -2168,11 +2199,11 @@ "dev": true }, "node_modules/basketry": { - "version": "0.2.0-alpha.13", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.13.tgz", - "integrity": "sha512-kGL+NsVKHlf2RJTafRR7uwlq/lfWxAHXL9mLsAuHZrx9X26Q2nnxHEQ0ZlV3OV9g+v76SQ8DB0R4S1+22lOrbQ==", + "version": "0.2.0-alpha.18", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.18.tgz", + "integrity": "sha512-2G1H9KZmNh2sUDeoJPVHdbS6HNZdjEWvzO/prDwHLMbhKMzmv03nL/ixEBctnTWR5OBpgpdP+4giqV/tbFPqMw==", "dependencies": { - "ajv": "^8.11.0", + "@basketry/ir": "^0.2.0-alpha.3", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", @@ -2186,21 +2217,6 @@ "url": "https://github.com/sponsors/basketry" } }, - "node_modules/basketry/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/basketry/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2267,11 +2283,6 @@ "node": ">=8" } }, - "node_modules/basketry/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/basketry/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8551,6 +8562,32 @@ "@babel/helper-validator-identifier": "^7.27.1" } }, + "@basketry/ir": { + "version": "0.2.0-alpha.3", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-alpha.3.tgz", + "integrity": "sha512-Ik8UH6GbI+jpOuDdZvnqFASZyicwzKsRStLVtQNvS9Q+eqbOSvJ0wzEkMYw9WmljZCl9U45uHIKDvdOTs07g4Q==", + "requires": { + "ajv": "^8.17.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, "@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -9785,11 +9822,11 @@ "dev": true }, "basketry": { - "version": "0.2.0-alpha.13", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.13.tgz", - "integrity": "sha512-kGL+NsVKHlf2RJTafRR7uwlq/lfWxAHXL9mLsAuHZrx9X26Q2nnxHEQ0ZlV3OV9g+v76SQ8DB0R4S1+22lOrbQ==", + "version": "0.2.0-alpha.18", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.18.tgz", + "integrity": "sha512-2G1H9KZmNh2sUDeoJPVHdbS6HNZdjEWvzO/prDwHLMbhKMzmv03nL/ixEBctnTWR5OBpgpdP+4giqV/tbFPqMw==", "requires": { - "ajv": "^8.11.0", + "@basketry/ir": "^0.2.0-alpha.3", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", @@ -9797,17 +9834,6 @@ "yargs": "^17.4.0" }, "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9853,11 +9879,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/package.json b/package.json index c39e52c..07582ce 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^4.6.4" }, "dependencies": { - "basketry": "^0.2.0-alpha.13", + "basketry": "^0.2.0-alpha.18", "case": "^1.6.3", "pluralize": "^8.0.0" } diff --git a/src/offset-pagination.test.ts b/src/offset-pagination.test.ts index cf7b87a..3cefd2a 100644 --- a/src/offset-pagination.test.ts +++ b/src/offset-pagination.test.ts @@ -393,12 +393,14 @@ const paginationParams = (): Parameter[] => [ name: build.stringLiteral('offset'), value: build.primitiveValue({ typeName: build.primitiveLiteral('integer'), + isOptional: build.trueLiteral(true), }), }), build.parameter({ name: build.stringLiteral('limit'), value: build.primitiveValue({ typeName: build.primitiveLiteral('integer'), + isOptional: build.trueLiteral(true), }), }), ]; diff --git a/src/relay-pagination.test.ts b/src/relay-pagination.test.ts index 67189ba..be1ad46 100644 --- a/src/relay-pagination.test.ts +++ b/src/relay-pagination.test.ts @@ -330,24 +330,28 @@ const paginationParams = (): Parameter[] => [ name: build.stringLiteral('first'), value: build.primitiveValue({ typeName: build.primitiveLiteral('integer'), + isOptional: build.trueLiteral(true), }), }), build.parameter({ name: build.stringLiteral('after'), value: build.primitiveValue({ typeName: build.primitiveLiteral('string'), + isOptional: build.trueLiteral(true), }), }), build.parameter({ name: build.stringLiteral('last'), value: build.primitiveValue({ typeName: build.primitiveLiteral('integer'), + isOptional: build.trueLiteral(true), }), }), build.parameter({ name: build.stringLiteral('before'), value: build.primitiveValue({ typeName: build.primitiveLiteral('string'), + isOptional: build.trueLiteral(true), }), }), ]; From 25190b1a9c3b4377f1bbfc827d2fba6f68db8192 Mon Sep 17 00:00:00 2001 From: skonves Date: Sat, 26 Jul 2025 23:32:40 +0000 Subject: [PATCH 07/11] 0.2.0-alpha.2 Co-authored-by: github-actions[bot] --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 23cc39a..30c44e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.1", + "version": "0.2.0-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@basketry/rules", - "version": "0.2.0-alpha.1", + "version": "0.2.0-alpha.2", "license": "MIT", "dependencies": { "basketry": "^0.2.0-alpha.18", diff --git a/package.json b/package.json index 07582ce..deba574 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.1", + "version": "0.2.0-alpha.2", "description": "Common rules for building Basketry pipelines", "main": "./lib/index.js", "scripts": { From 45b8acc6da51e8a1d9445ec7cc4a77b0eba67e58 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Thu, 31 Jul 2025 08:11:17 -0700 Subject: [PATCH 08/11] Upgrade basketry to RC --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30c44e6..3fdd6fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.0-alpha.2", "license": "MIT", "dependencies": { - "basketry": "^0.2.0-alpha.18", + "basketry": "^0.2.0-rc.2", "case": "^1.6.3", "pluralize": "^8.0.0" }, @@ -534,9 +534,9 @@ } }, "node_modules/@basketry/ir": { - "version": "0.2.0-alpha.3", - "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-alpha.3.tgz", - "integrity": "sha512-Ik8UH6GbI+jpOuDdZvnqFASZyicwzKsRStLVtQNvS9Q+eqbOSvJ0wzEkMYw9WmljZCl9U45uHIKDvdOTs07g4Q==", + "version": "0.2.0-rc.1", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-rc.1.tgz", + "integrity": "sha512-iwgGBkj7sJAaqfA7nLPAa/xULL5qHsPRobO83CS4EI639td5uSFrXVuRnkgGjbAPuK2zYw14Ui+s+SZuoQ9ThQ==", "dependencies": { "ajv": "^8.17.1" }, @@ -2199,11 +2199,11 @@ "dev": true }, "node_modules/basketry": { - "version": "0.2.0-alpha.18", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.18.tgz", - "integrity": "sha512-2G1H9KZmNh2sUDeoJPVHdbS6HNZdjEWvzO/prDwHLMbhKMzmv03nL/ixEBctnTWR5OBpgpdP+4giqV/tbFPqMw==", + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-rc.2.tgz", + "integrity": "sha512-XQjK+HjuLZcx5WXkGSNAToIsc5WaTq5TWWOac0dtnHkiVq3LZUrvzhzZXt0J1FoYByB48iz+XiJbwm16V3673g==", "dependencies": { - "@basketry/ir": "^0.2.0-alpha.3", + "@basketry/ir": "^0.2.0-rc.1", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", @@ -8563,9 +8563,9 @@ } }, "@basketry/ir": { - "version": "0.2.0-alpha.3", - "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-alpha.3.tgz", - "integrity": "sha512-Ik8UH6GbI+jpOuDdZvnqFASZyicwzKsRStLVtQNvS9Q+eqbOSvJ0wzEkMYw9WmljZCl9U45uHIKDvdOTs07g4Q==", + "version": "0.2.0-rc.1", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-rc.1.tgz", + "integrity": "sha512-iwgGBkj7sJAaqfA7nLPAa/xULL5qHsPRobO83CS4EI639td5uSFrXVuRnkgGjbAPuK2zYw14Ui+s+SZuoQ9ThQ==", "requires": { "ajv": "^8.17.1" }, @@ -9822,11 +9822,11 @@ "dev": true }, "basketry": { - "version": "0.2.0-alpha.18", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-alpha.18.tgz", - "integrity": "sha512-2G1H9KZmNh2sUDeoJPVHdbS6HNZdjEWvzO/prDwHLMbhKMzmv03nL/ixEBctnTWR5OBpgpdP+4giqV/tbFPqMw==", + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-rc.2.tgz", + "integrity": "sha512-XQjK+HjuLZcx5WXkGSNAToIsc5WaTq5TWWOac0dtnHkiVq3LZUrvzhzZXt0J1FoYByB48iz+XiJbwm16V3673g==", "requires": { - "@basketry/ir": "^0.2.0-alpha.3", + "@basketry/ir": "^0.2.0-rc.1", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", diff --git a/package.json b/package.json index deba574..95229dc 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^4.6.4" }, "dependencies": { - "basketry": "^0.2.0-alpha.18", + "basketry": "^0.2.0-rc.2", "case": "^1.6.3", "pluralize": "^8.0.0" } From b0070f53d124c52ceb8ad4671dcd64432e041d40 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Thu, 31 Jul 2025 08:11:33 -0700 Subject: [PATCH 09/11] chore: npm audit fix --- package-lock.json | 321 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 274 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3fdd6fe..ac0d941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2320,9 +2320,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "dependencies": { "balanced-match": "^1.0.0", @@ -2416,6 +2416,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2779,6 +2792,20 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.132", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.132.tgz", @@ -2845,6 +2872,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -3667,14 +3739,16 @@ "dev": true }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -3701,10 +3775,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -3730,14 +3807,24 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3752,6 +3839,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -3847,6 +3947,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -3884,9 +3996,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -3896,12 +4008,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3910,6 +4022,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -6391,6 +6515,15 @@ "tmpl": "1.0.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -9909,9 +10042,9 @@ } }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -9980,6 +10113,16 @@ "get-intrinsic": "^1.0.2" } }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -10264,6 +10407,17 @@ } } }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "electron-to-chromium": { "version": "1.4.132", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.132.tgz", @@ -10318,6 +10472,39 @@ "unbox-primitive": "^1.0.1" } }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -10940,14 +11127,16 @@ "dev": true }, "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" } }, "fs.realpath": { @@ -10964,9 +11153,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "functional-red-black-tree": { @@ -10987,14 +11176,21 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" } }, "get-package-type": { @@ -11003,6 +11199,16 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -11065,6 +11271,12 @@ "slash": "^3.0.0" } }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -11093,18 +11305,27 @@ "dev": true }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true }, "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" } }, "hosted-git-info": { @@ -12952,6 +13173,12 @@ "tmpl": "1.0.5" } }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true + }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", From ddf5aa010c506090327d6e00f21f69d479394a5c Mon Sep 17 00:00:00 2001 From: skonves Date: Thu, 31 Jul 2025 15:15:15 +0000 Subject: [PATCH 10/11] 0.2.0-rc.0 Co-authored-by: github-actions[bot] --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac0d941..0208a3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.2", + "version": "0.2.0-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@basketry/rules", - "version": "0.2.0-alpha.2", + "version": "0.2.0-rc.0", "license": "MIT", "dependencies": { "basketry": "^0.2.0-rc.2", diff --git a/package.json b/package.json index 95229dc..7e807cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@basketry/rules", - "version": "0.2.0-alpha.2", + "version": "0.2.0-rc.0", "description": "Common rules for building Basketry pipelines", "main": "./lib/index.js", "scripts": { From 9306c83f997bce79d57cfc88ee30a26a992679c3 Mon Sep 17 00:00:00 2001 From: Steve Konves Date: Sun, 10 Aug 2025 16:42:18 -0700 Subject: [PATCH 11/11] Upgrade to latest packages --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0208a3b..f5d3595 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.0-rc.0", "license": "MIT", "dependencies": { - "basketry": "^0.2.0-rc.2", + "basketry": "^0.2.0", "case": "^1.6.3", "pluralize": "^8.0.0" }, @@ -534,9 +534,9 @@ } }, "node_modules/@basketry/ir": { - "version": "0.2.0-rc.1", - "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-rc.1.tgz", - "integrity": "sha512-iwgGBkj7sJAaqfA7nLPAa/xULL5qHsPRobO83CS4EI639td5uSFrXVuRnkgGjbAPuK2zYw14Ui+s+SZuoQ9ThQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0.tgz", + "integrity": "sha512-jHUGjuj6DlLMPn657PN/+jvzytBU8DBvQ5hJ24Qn2eM0JEUXc6hXAgyowXns8a3/q0AFwNNUwOCiYSULY8SDuw==", "dependencies": { "ajv": "^8.17.1" }, @@ -2199,11 +2199,11 @@ "dev": true }, "node_modules/basketry": { - "version": "0.2.0-rc.2", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-rc.2.tgz", - "integrity": "sha512-XQjK+HjuLZcx5WXkGSNAToIsc5WaTq5TWWOac0dtnHkiVq3LZUrvzhzZXt0J1FoYByB48iz+XiJbwm16V3673g==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0.tgz", + "integrity": "sha512-LLd6QdP/2Mnhm2YGDnW5m95/bYaAJJYuuNeDLL/V2ohptorfFJcpnJFrMrfXWMGCnoQDd4ICPTiayKLoXqCkUw==", "dependencies": { - "@basketry/ir": "^0.2.0-rc.1", + "@basketry/ir": "^0.2.0", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", @@ -8696,9 +8696,9 @@ } }, "@basketry/ir": { - "version": "0.2.0-rc.1", - "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0-rc.1.tgz", - "integrity": "sha512-iwgGBkj7sJAaqfA7nLPAa/xULL5qHsPRobO83CS4EI639td5uSFrXVuRnkgGjbAPuK2zYw14Ui+s+SZuoQ9ThQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@basketry/ir/-/ir-0.2.0.tgz", + "integrity": "sha512-jHUGjuj6DlLMPn657PN/+jvzytBU8DBvQ5hJ24Qn2eM0JEUXc6hXAgyowXns8a3/q0AFwNNUwOCiYSULY8SDuw==", "requires": { "ajv": "^8.17.1" }, @@ -9955,11 +9955,11 @@ "dev": true }, "basketry": { - "version": "0.2.0-rc.2", - "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0-rc.2.tgz", - "integrity": "sha512-XQjK+HjuLZcx5WXkGSNAToIsc5WaTq5TWWOac0dtnHkiVq3LZUrvzhzZXt0J1FoYByB48iz+XiJbwm16V3673g==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/basketry/-/basketry-0.2.0.tgz", + "integrity": "sha512-LLd6QdP/2Mnhm2YGDnW5m95/bYaAJJYuuNeDLL/V2ohptorfFJcpnJFrMrfXWMGCnoQDd4ICPTiayKLoXqCkUw==", "requires": { - "@basketry/ir": "^0.2.0-rc.1", + "@basketry/ir": "^0.2.0", "case": "^1.6.3", "chalk": "^4.1.2", "ts-node": "^10.7.0", diff --git a/package.json b/package.json index 7e807cd..4e9cfb4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^4.6.4" }, "dependencies": { - "basketry": "^0.2.0-rc.2", + "basketry": "^0.2.0", "case": "^1.6.3", "pluralize": "^8.0.0" }