nalloc 0.2.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +326 -178
  2. package/build/codemod-cli.cjs +153 -0
  3. package/build/codemod-cli.cjs.map +1 -0
  4. package/build/codemod-cli.d.ts +2 -0
  5. package/build/codemod-cli.js +103 -0
  6. package/build/codemod-cli.js.map +1 -0
  7. package/build/codemod.cjs +652 -0
  8. package/build/codemod.cjs.map +1 -0
  9. package/build/codemod.d.ts +29 -0
  10. package/build/codemod.js +634 -0
  11. package/build/codemod.js.map +1 -0
  12. package/build/eslint.cjs +221 -0
  13. package/build/eslint.cjs.map +1 -0
  14. package/build/eslint.d.ts +36 -0
  15. package/build/eslint.js +198 -0
  16. package/build/eslint.js.map +1 -0
  17. package/build/http.cjs +31 -0
  18. package/build/http.cjs.map +1 -0
  19. package/build/http.d.ts +31 -0
  20. package/build/http.js +13 -0
  21. package/build/http.js.map +1 -0
  22. package/build/nonempty.cjs +35 -0
  23. package/build/nonempty.cjs.map +1 -0
  24. package/build/nonempty.d.ts +34 -0
  25. package/build/nonempty.js +14 -0
  26. package/build/nonempty.js.map +1 -0
  27. package/build/option.cjs +1 -1
  28. package/build/option.cjs.map +1 -1
  29. package/build/option.d.ts +2 -2
  30. package/build/option.js +1 -1
  31. package/build/option.js.map +1 -1
  32. package/build/result.cjs +10 -18
  33. package/build/result.cjs.map +1 -1
  34. package/build/result.d.ts +3 -34
  35. package/build/result.js +10 -15
  36. package/build/result.js.map +1 -1
  37. package/build/safe.cjs +8 -0
  38. package/build/safe.cjs.map +1 -1
  39. package/build/safe.d.ts +3 -0
  40. package/build/safe.js +2 -0
  41. package/build/safe.js.map +1 -1
  42. package/build/schema.cjs +32 -0
  43. package/build/schema.cjs.map +1 -0
  44. package/build/schema.d.ts +44 -0
  45. package/build/schema.js +14 -0
  46. package/build/schema.js.map +1 -0
  47. package/package.json +63 -10
  48. package/src/__tests__/codemod.ts +211 -0
  49. package/src/__tests__/eslint.ts +99 -0
  50. package/src/__tests__/fixtures/tsconfig.json +10 -0
  51. package/src/__tests__/http.ts +64 -0
  52. package/src/__tests__/iter.ts +18 -0
  53. package/src/__tests__/nonempty.ts +46 -0
  54. package/src/__tests__/nonempty.types.ts +38 -0
  55. package/src/__tests__/option.ts +4 -0
  56. package/src/__tests__/result.ts +104 -129
  57. package/src/__tests__/result.types.ts +2 -2
  58. package/src/__tests__/schema.ts +58 -0
  59. package/src/codemod-cli.ts +108 -0
  60. package/src/codemod.ts +623 -0
  61. package/src/eslint.ts +145 -0
  62. package/src/http.ts +42 -0
  63. package/src/nonempty.ts +48 -0
  64. package/src/option.ts +3 -4
  65. package/src/result.ts +18 -49
  66. package/src/safe.ts +3 -0
  67. package/src/schema.ts +52 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/codemod.ts"],"sourcesContent":["import { parseSync } from 'oxc-parser';\n\n/** A call site the codemod refused to convert, with the reason for manual review. */\nexport interface SkippedSite {\n readonly file: string;\n readonly line: number;\n readonly reason: 'result-async' | 'safe-try' | 'unsupported' | 'namespace-import';\n readonly text: string;\n}\n\nexport interface MigrateFileResult {\n readonly output: string;\n readonly changed: boolean;\n readonly converted: number;\n readonly skipped: SkippedSite[];\n}\n\ninterface Node {\n type: string;\n start: number;\n end: number;\n [key: string]: unknown;\n}\n\ninterface Edit {\n start: number;\n end: number;\n text: string;\n}\n\n/** neverthrow instance method -> nalloc Result function. Ambiguous names (shared with Array/other types) convert only with provenance. */\nconst INSTANCE_METHODS: ReadonlyMap<string, { readonly fn: string; readonly ambiguous?: boolean }> = new Map([\n ['map', { fn: 'map', ambiguous: true }],\n ['mapErr', { fn: 'mapErr' }],\n ['andThen', { fn: 'flatMap' }],\n ['orElse', { fn: 'orElse' }],\n ['match', { fn: 'match' }],\n ['unwrapOr', { fn: 'unwrapOr' }],\n ['isOk', { fn: 'isOk' }],\n ['isErr', { fn: 'isErr' }],\n ['andTee', { fn: 'tap' }],\n ['orTee', { fn: 'tapErr' }],\n ['_unsafeUnwrap', { fn: 'unwrap' }],\n ['_unsafeUnwrapErr', { fn: 'unwrapErr' }],\n]);\n\nconst ASYNC_INSTANCE_METHODS: ReadonlySet<string> = new Set(['asyncMap', 'asyncAndThen', 'asyncAndThrough']);\nconst UNSUPPORTED_INSTANCE_METHODS: ReadonlySet<string> = new Set(['andThrough', 'safeUnwrap']);\n\n/** neverthrow module-level names that produce ResultAsync - left on neverthrow, reported for manual genAsync migration. */\nconst ASYNC_IMPORTS: ReadonlySet<string> = new Set(['ResultAsync', 'okAsync', 'errAsync', 'fromSafePromise', 'fromAsyncThrowable']);\n\nconst STATIC_METHODS: ReadonlyMap<string, string> = new Map([\n ['fromThrowable', 'wrap'],\n ['combine', 'all'],\n ['combineWithAllErrors', 'collectAll'],\n]);\n\nfunction isNode(value: unknown): value is Node {\n return typeof value === 'object' && value !== null && typeof (value as Node).type === 'string';\n}\n\nfunction eachChild(node: Node, visit: (child: Node) => void): void {\n for (const key of Object.keys(node)) {\n const value = node[key];\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isNode(item)) visit(item);\n }\n } else if (isNode(value)) {\n visit(value);\n }\n }\n}\n\nfunction annotationTypeName(id: Node): string | undefined {\n const annotation = id.typeAnnotation as Node | null;\n const ref = annotation?.typeAnnotation as Node | undefined;\n if (ref?.type !== 'TSTypeReference') return undefined;\n const typeName = ref.typeName as Node;\n return typeName.type === 'Identifier' ? (typeName.name as string) : undefined;\n}\n\ninterface ImportedNames {\n /** local name -> imported name, for every value imported from neverthrow */\n readonly locals: Map<string, string>;\n /** import declarations to replace */\n readonly declarations: Node[];\n readonly hasNamespace: boolean;\n}\n\nfunction collectImports(program: Node): ImportedNames {\n const locals = new Map<string, string>();\n const declarations: Node[] = [];\n let hasNamespace = false;\n for (const stmt of program.body as Node[]) {\n if (stmt.type !== 'ImportDeclaration' || (stmt.source as Node & { value: string }).value !== 'neverthrow') continue;\n declarations.push(stmt);\n for (const spec of stmt.specifiers as Node[]) {\n if (spec.type === 'ImportNamespaceSpecifier') {\n hasNamespace = true;\n } else if (spec.type === 'ImportSpecifier') {\n const imported = spec.imported as Node;\n if (imported.type === 'Identifier') {\n locals.set((spec.local as Node).name as string, imported.name as string);\n }\n }\n }\n }\n return { locals, declarations, hasNamespace };\n}\n\nclass FileMigration {\n readonly edits: Edit[] = [];\n readonly skipped: SkippedSite[] = [];\n /** identifiers proven to hold a (migrated) Result */\n readonly resultIds = new Set<string>();\n /** identifiers holding neverthrow ResultAsync values - never convert methods on these */\n readonly asyncIds = new Set<string>();\n /** identifiers bound to fromThrowable-wrapped functions - their call results are Results */\n readonly wrappedFns = new Set<string>();\n /** local functions declared to return Result */\n readonly resultFns = new Set<string>();\n /** identifiers also bound to something unclassifiable - provenance dropped */\n readonly conflicted = new Set<string>();\n readonly residualNames = new Set<string>();\n converted = 0;\n needsNamespace = false;\n needsPipe = false;\n needsResultType = false;\n readonly usedTypeNames = new Set<string>();\n\n constructor(\n readonly file: string,\n readonly source: string,\n readonly imports: ImportedNames,\n ) {}\n\n importedAs(local: string): string | undefined {\n return this.imports.locals.get(local);\n }\n\n isFromPromiseCall(node: Node): boolean {\n return (\n node.type === 'CallExpression' && (node.callee as Node).type === 'Identifier' && this.importedAs((node.callee as Node).name as string) === 'fromPromise'\n );\n }\n\n lineOf(offset: number): number {\n let line = 1;\n for (let i = 0; i < offset; i++) {\n if (this.source.charCodeAt(i) === 10) line++;\n }\n return line;\n }\n\n report(reason: SkippedSite['reason'], node: Node): void {\n this.skipped.push({\n file: this.file,\n line: this.lineOf(node.start),\n reason,\n text: this.source.slice(node.start, Math.min(node.end, node.start + 120)),\n });\n }\n\n /** Classifies an expression as a migrated Result ('result'), a neverthrow ResultAsync ('async'), or unknown. */\n classify(node: Node): 'result' | 'async' | undefined {\n if (node.type === 'Identifier') {\n const name = node.name as string;\n if (this.conflicted.has(name)) return undefined;\n if (this.asyncIds.has(name)) return 'async';\n if (this.resultIds.has(name)) return 'result';\n return undefined;\n }\n if (node.type === 'AwaitExpression') {\n // a directly-awaited fromPromise is converted to Result.fromPromise, so its result is a migrated Result;\n // awaiting any other ResultAsync yields a neverthrow Result instance, which must stay on neverthrow\n if (this.isFromPromiseCall(node.argument as Node)) return 'result';\n return this.classify(node.argument as Node) === 'async' ? 'async' : undefined;\n }\n if (node.type === 'CallExpression') {\n const callee = node.callee as Node;\n if (callee.type === 'Identifier') {\n const name = callee.name as string;\n const imported = this.importedAs(name);\n if (imported === 'ok' || imported === 'err' || imported === 'combine' || imported === 'combineWithAllErrors') return 'result';\n if (imported !== undefined && (ASYNC_IMPORTS.has(imported) || imported === 'fromPromise')) return 'async';\n if (this.wrappedFns.has(name) || this.resultFns.has(name)) return 'result';\n return undefined;\n }\n if (callee.type === 'MemberExpression' && !(callee.computed as boolean)) {\n const property = callee.property as Node;\n const object = callee.object as Node;\n if (property.type !== 'Identifier') return undefined;\n const method = property.name as string;\n if (object.type === 'Identifier') {\n const objImported = this.importedAs(object.name as string);\n if (objImported === 'Result' && STATIC_METHODS.has(method)) {\n return method === 'fromThrowable' ? undefined : 'result';\n }\n if (objImported === 'ResultAsync') return 'async';\n }\n const receiver = this.classify(object);\n if (receiver === 'async') return 'async';\n if (receiver === 'result') {\n if (ASYNC_INSTANCE_METHODS.has(method)) return 'async';\n if (INSTANCE_METHODS.has(method)) return 'result';\n }\n return undefined;\n }\n }\n return undefined;\n }\n\n classifyBinding(id: Node, init: Node | null): void {\n if (id.type !== 'Identifier') return;\n const name = id.name as string;\n const typeName = annotationTypeName(id);\n const annotated = typeName !== undefined ? this.importedAs(typeName) : undefined;\n const fromInit = ((): 'result' | 'async' | 'wrapped' | undefined => {\n if (init === null) return undefined;\n if (init.type === 'CallExpression') {\n const callee = init.callee as Node;\n const calleeImported = callee.type === 'Identifier' ? this.importedAs(callee.name as string) : undefined;\n if (calleeImported === 'fromThrowable') return 'wrapped';\n if (callee.type === 'MemberExpression') {\n const object = callee.object as Node;\n const property = callee.property as Node;\n if (\n object.type === 'Identifier' &&\n property.type === 'Identifier' &&\n this.importedAs(object.name as string) === 'Result' &&\n property.name === 'fromThrowable'\n ) {\n return 'wrapped';\n }\n }\n }\n return this.classify(init);\n })();\n const kind = annotated === 'Result' || annotated === 'Ok' || annotated === 'Err' ? 'result' : annotated === 'ResultAsync' ? 'async' : fromInit;\n if (kind === 'result') {\n this.addClassified(name, this.resultIds);\n } else if (kind === 'async') {\n this.addClassified(name, this.asyncIds);\n } else if (kind === 'wrapped') {\n this.addClassified(name, this.wrappedFns);\n } else {\n // a second, unclassifiable binding of a known name poisons its provenance\n if (this.resultIds.has(name) || this.asyncIds.has(name) || this.wrappedFns.has(name)) {\n this.conflicted.add(name);\n }\n }\n }\n\n addClassified(name: string, target: Set<string>): void {\n if ((this.resultIds.has(name) || this.asyncIds.has(name) || this.wrappedFns.has(name)) && !target.has(name)) {\n this.conflicted.add(name);\n return;\n }\n target.add(name);\n }\n\n collectProvenance(node: Node): void {\n if (node.type === 'VariableDeclarator') {\n this.classifyBinding(node.id as Node, node.init as Node | null);\n } else if (node.type === 'AssignmentExpression' && node.operator === '=') {\n this.classifyBinding(node.left as Node, node.right as Node);\n } else if (node.type === 'FunctionDeclaration' || node.type === 'TSDeclareFunction') {\n const id = node.id as Node | null;\n const returnType = node.returnType as Node | null;\n if (id?.type === 'Identifier' && returnType !== null) {\n const ref = returnType.typeAnnotation as Node;\n if (ref.type === 'TSTypeReference' && (ref.typeName as Node).type === 'Identifier') {\n const imported = this.importedAs((ref.typeName as Node).name as string);\n if (imported === 'Result') this.resultFns.add(id.name as string);\n }\n }\n for (const param of node.params as Node[]) {\n this.classifyBinding(param, null);\n }\n } else if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {\n for (const param of node.params as Node[]) {\n this.classifyBinding(param, null);\n }\n }\n eachChild(node, (child) => this.collectProvenance(child));\n }\n\n /** Removes and returns collected edits falling inside a span. */\n takeEditsWithin(start: number, end: number): Edit[] {\n const inside: Edit[] = [];\n for (let i = this.edits.length - 1; i >= 0; i--) {\n const edit = this.edits[i];\n if (edit.start >= start && edit.end <= end) {\n inside.push(edit);\n this.edits.splice(i, 1);\n }\n }\n return inside;\n }\n\n /** Renders a source span with any already-collected nested edits applied. */\n render(start: number, end: number): string {\n const inside = this.takeEditsWithin(start, end).sort((a, b) => b.start - a.start);\n let text = this.source.slice(start, end);\n for (const edit of inside) {\n text = text.slice(0, edit.start - start) + edit.text + text.slice(edit.end - start);\n }\n return text;\n }\n\n renderArgs(args: Node[]): string {\n if (args.length === 0) return '';\n return this.render(args[0].start, args[args.length - 1].end);\n }\n\n convert(node: Node, parent: Node | undefined, grandparent: Node | undefined): void {\n if (node.type === 'TSTypeReference') {\n const typeName = node.typeName as Node;\n if (typeName.type === 'Identifier') {\n const imported = this.importedAs(typeName.name as string);\n if (imported === 'Result') {\n this.edits.push({ start: typeName.start, end: typeName.end, text: 'ResultType' });\n this.needsResultType = true;\n } else if (imported === 'Ok' || imported === 'Err') {\n this.usedTypeNames.add(imported);\n }\n }\n }\n\n if (node.type === 'CallExpression') {\n // an outer convertible chain link processes this node itself; skip to avoid double conversion\n const consumedByOuterChain =\n parent?.type === 'MemberExpression' &&\n parent.object === node &&\n !(parent.computed as boolean) &&\n (parent.property as Node).type === 'Identifier' &&\n grandparent?.type === 'CallExpression' &&\n grandparent.callee === parent &&\n (INSTANCE_METHODS.has((parent.property as Node).name as string) ||\n ASYNC_INSTANCE_METHODS.has((parent.property as Node).name as string) ||\n UNSUPPORTED_INSTANCE_METHODS.has((parent.property as Node).name as string));\n if (!consumedByOuterChain && this.convertCall(node)) return;\n }\n\n eachChild(node, (child) => this.convert(child, node, parent));\n }\n\n /** Returns true when the node was fully handled (children already converted as needed). */\n convertCall(node: Node): boolean {\n const callee = node.callee as Node;\n\n if (callee.type === 'Identifier') {\n const imported = this.importedAs(callee.name as string);\n if (imported === undefined) return false;\n if (imported === 'fromThrowable' || imported === 'combine' || imported === 'combineWithAllErrors') {\n this.edits.push({ start: callee.start, end: callee.end, text: `Result.${STATIC_METHODS.get(imported)}` });\n this.needsNamespace = true;\n this.converted++;\n return false;\n }\n if (imported === 'safeTry') {\n this.report('safe-try', node);\n this.residualNames.add(callee.name as string);\n return false;\n }\n if (ASYNC_IMPORTS.has(imported)) {\n this.report('result-async', node);\n this.residualNames.add(callee.name as string);\n return false;\n }\n return false;\n }\n\n if (callee.type !== 'MemberExpression' || (callee.computed as boolean) || (callee.property as Node).type !== 'Identifier') {\n return false;\n }\n const object = callee.object as Node;\n const method = (callee.property as Node).name as string;\n\n if (object.type === 'Identifier') {\n const objImported = this.importedAs(object.name as string);\n if (objImported === 'Result' && STATIC_METHODS.has(method)) {\n this.edits.push({ start: callee.start, end: callee.end, text: `Result.${STATIC_METHODS.get(method)}` });\n this.needsNamespace = true;\n this.converted++;\n return false;\n }\n if (objImported === 'ResultAsync') {\n this.report('result-async', node);\n this.residualNames.add(object.name as string);\n return false;\n }\n }\n\n if (!INSTANCE_METHODS.has(method) && !ASYNC_INSTANCE_METHODS.has(method) && !UNSUPPORTED_INSTANCE_METHODS.has(method)) {\n return false;\n }\n\n // collect the full chain from this outermost call down to its base receiver\n const links: { call: Node; method: string }[] = [];\n let current: Node = node;\n let blocked: SkippedSite['reason'] | undefined;\n while (true) {\n const currentCallee = current.callee as Node;\n const currentMethod = (currentCallee.property as Node).name as string;\n if (ASYNC_INSTANCE_METHODS.has(currentMethod)) {\n blocked = 'result-async';\n break;\n }\n if (UNSUPPORTED_INSTANCE_METHODS.has(currentMethod)) {\n blocked = 'unsupported';\n break;\n }\n links.unshift({ call: current, method: currentMethod });\n const receiver = currentCallee.object as Node;\n if (\n receiver.type === 'CallExpression' &&\n (receiver.callee as Node).type === 'MemberExpression' &&\n !((receiver.callee as Node).computed as boolean) &&\n ((receiver.callee as Node).property as Node).type === 'Identifier' &&\n (INSTANCE_METHODS.has(((receiver.callee as Node).property as Node).name as string) ||\n ASYNC_INSTANCE_METHODS.has(((receiver.callee as Node).property as Node).name as string) ||\n UNSUPPORTED_INSTANCE_METHODS.has(((receiver.callee as Node).property as Node).name as string))\n ) {\n current = receiver;\n continue;\n }\n break;\n }\n\n if (blocked !== undefined) {\n // converting inner links would leave a neverthrow method called on a nalloc value\n this.report(blocked, node);\n const blockedCall = current;\n eachChild(node, (child) => {\n if (child !== blockedCall) this.convert(child, node, undefined);\n });\n return true;\n }\n\n const base = (links[0].call.callee as Node).object as Node;\n const baseKind = this.classify(base);\n if (baseKind === 'async') {\n this.report('result-async', node);\n return true;\n }\n const hasExclusive = links.some((link) => !INSTANCE_METHODS.get(link.method)!.ambiguous);\n if (baseKind !== 'result' && !hasExclusive) {\n // unprovable receiver and only ambiguous methods (e.g. bare .map) - almost certainly not a Result\n return false;\n }\n\n // convert nested code inside the base and every argument first, so render() picks the edits up\n this.convert(base, undefined, undefined);\n for (const link of links) {\n for (const arg of link.call.arguments as Node[]) {\n this.convert(arg, link.call, undefined);\n }\n }\n\n const baseText = this.render(base.start, base.end);\n this.needsNamespace = true;\n this.converted += links.length;\n const replacement = ((): string => {\n if (links.length === 1) {\n const { fn } = INSTANCE_METHODS.get(links[0].method)!;\n const args = this.renderArgs(links[0].call.arguments as Node[]);\n return `Result.${fn}(${baseText}${args.length > 0 ? `, ${args}` : ''})`;\n }\n this.needsPipe = true;\n const steps = links.map((link) => {\n const { fn } = INSTANCE_METHODS.get(link.method)!;\n const args = this.renderArgs(link.call.arguments as Node[]);\n return `($r) => Result.${fn}($r${args.length > 0 ? `, ${args}` : ''})`;\n });\n return `pipe(${baseText}, ${steps.join(', ')})`;\n })();\n this.edits.push({ start: node.start, end: node.end, text: replacement });\n return true;\n }\n\n readonly awaitedFromPromise = new Set<Node>();\n\n /** Direct `await fromPromise(...)` resolves to a plain Result and maps 1:1 to nalloc. */\n convertAwaitedFromPromise(node: Node): void {\n if (node.type === 'AwaitExpression' && this.isFromPromiseCall(node.argument as Node)) {\n const call = node.argument as Node;\n this.edits.push({ start: (call.callee as Node).start, end: (call.callee as Node).end, text: 'Result.fromPromise' });\n this.awaitedFromPromise.add(call);\n this.needsNamespace = true;\n this.converted++;\n }\n eachChild(node, (child) => this.convertAwaitedFromPromise(child));\n }\n\n reportUnconvertedFromPromise(node: Node): void {\n if (this.isFromPromiseCall(node) && !this.awaitedFromPromise.has(node)) {\n this.report('result-async', node);\n this.residualNames.add((node.callee as Node).name as string);\n }\n eachChild(node, (child) => this.reportUnconvertedFromPromise(child));\n }\n\n rewriteImports(): void {\n const valueNames: string[] = [];\n const typeNames: string[] = [];\n for (const [local, imported] of this.imports.locals) {\n if (imported === 'ok' || imported === 'err') {\n valueNames.push(imported === local ? imported : `${imported} as ${local}`);\n }\n }\n if (this.needsNamespace) valueNames.push('Result');\n if (this.needsPipe) valueNames.push('pipe');\n if (this.needsResultType) typeNames.push('type ResultType');\n for (const name of this.usedTypeNames) typeNames.push(`type ${name}`);\n\n const statements: string[] = [];\n const names = [...valueNames, ...typeNames];\n if (names.length > 0) {\n statements.push(`import { ${names.join(', ')} } from 'nalloc';`);\n }\n const residual = [...this.residualNames].map((local) => {\n const imported = this.importedAs(local)!;\n return imported === local ? imported : `${imported} as ${local}`;\n });\n if (residual.length > 0) {\n statements.push(`import { ${residual.join(', ')} } from 'neverthrow';`);\n }\n\n const [first, ...rest] = this.imports.declarations;\n this.edits.push({ start: first.start, end: first.end, text: statements.join('\\n') });\n for (const decl of rest) {\n const end = this.source.charCodeAt(decl.end) === 10 ? decl.end + 1 : decl.end;\n this.edits.push({ start: decl.start, end, text: '' });\n }\n }\n\n apply(): string {\n const sorted = [...this.edits].sort((a, b) => b.start - a.start);\n let output = this.source;\n for (const edit of sorted) {\n output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);\n }\n return output;\n }\n}\n\n/**\n * Migrates one source file from neverthrow to nalloc.\n * Pure function: parses, rewrites provable sites via text splices (formatting preserved),\n * and reports everything it refuses to convert.\n * @param source - The file's source text\n * @param file - File path used in the report\n * @returns The migrated source, whether it changed, and the skipped sites\n */\nexport function migrateSource(source: string, file: string): MigrateFileResult {\n const parsed = parseSync(file, source);\n if (parsed.errors.some((e) => e.severity === 'Error')) {\n return {\n output: source,\n changed: false,\n converted: 0,\n skipped: [{ file, line: 1, reason: 'unsupported', text: 'file has parse errors' }],\n };\n }\n const program = parsed.program as unknown as Node;\n const imports = collectImports(program);\n if (imports.declarations.length === 0) {\n return { output: source, changed: false, converted: 0, skipped: [] };\n }\n const migration = new FileMigration(file, source, imports);\n if (imports.hasNamespace) {\n migration.report('namespace-import', imports.declarations[0]);\n return { output: source, changed: false, converted: 0, skipped: migration.skipped };\n }\n migration.collectProvenance(program);\n migration.convertAwaitedFromPromise(program);\n migration.convert(program, undefined, undefined);\n migration.reportUnconvertedFromPromise(program);\n migration.rewriteImports();\n const output = migration.apply();\n return {\n output,\n changed: output !== source,\n converted: migration.converted,\n skipped: migration.skipped,\n };\n}\n\nexport interface MigrationReport {\n readonly filesChanged: number;\n readonly converted: number;\n readonly skipped: readonly SkippedSite[];\n}\n\n/** Renders the skipped-site report as markdown for --report. */\nexport function renderReport(report: MigrationReport): string {\n const lines = [\n '# nalloc migration report',\n '',\n `Files changed: ${report.filesChanged}. Sites converted: ${report.converted}. Sites needing manual review: ${report.skipped.length}.`,\n '',\n ];\n const byFile = new Map<string, SkippedSite[]>();\n for (const site of report.skipped) {\n const sites = byFile.get(site.file);\n if (sites === undefined) {\n byFile.set(site.file, [site]);\n } else {\n sites.push(site);\n }\n }\n for (const [file, sites] of byFile) {\n lines.push(`## ${file}`, '');\n for (const site of sites) {\n lines.push(`- line ${site.line} [${site.reason}]: \\`${site.text}\\``);\n }\n lines.push('');\n }\n return lines.join('\\n');\n}\n"],"names":["parseSync","INSTANCE_METHODS","Map","fn","ambiguous","ASYNC_INSTANCE_METHODS","Set","UNSUPPORTED_INSTANCE_METHODS","ASYNC_IMPORTS","STATIC_METHODS","isNode","value","type","eachChild","node","visit","key","Object","keys","Array","isArray","item","annotationTypeName","id","annotation","typeAnnotation","ref","undefined","typeName","name","collectImports","program","locals","declarations","hasNamespace","stmt","body","source","push","spec","specifiers","imported","set","local","FileMigration","edits","skipped","resultIds","asyncIds","wrappedFns","resultFns","conflicted","residualNames","converted","needsNamespace","needsPipe","needsResultType","usedTypeNames","file","imports","importedAs","get","isFromPromiseCall","callee","lineOf","offset","line","i","charCodeAt","report","reason","start","text","slice","Math","min","end","classify","has","argument","computed","property","object","method","objImported","receiver","classifyBinding","init","annotated","fromInit","calleeImported","kind","addClassified","add","target","collectProvenance","operator","left","right","returnType","param","params","child","takeEditsWithin","inside","length","edit","splice","render","sort","a","b","renderArgs","args","convert","parent","grandparent","consumedByOuterChain","convertCall","links","current","blocked","currentCallee","currentMethod","unshift","call","blockedCall","base","baseKind","hasExclusive","some","link","arg","arguments","baseText","replacement","steps","map","join","awaitedFromPromise","convertAwaitedFromPromise","reportUnconvertedFromPromise","rewriteImports","valueNames","typeNames","statements","names","residual","first","rest","decl","apply","sorted","output","migrateSource","parsed","errors","e","severity","changed","migration","renderReport","lines","filesChanged","byFile","site","sites"],"mappings":"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"}
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get default () {
13
+ return _default;
14
+ },
15
+ get mustUse () {
16
+ return mustUse;
17
+ },
18
+ get noUnwrap () {
19
+ return noUnwrap;
20
+ },
21
+ get rules () {
22
+ return rules;
23
+ }
24
+ });
25
+ const _utils = require("@typescript-eslint/utils");
26
+ const createRule = _utils.ESLintUtils.RuleCreator((name)=>`https://github.com/3axap4eHko/nalloc#${name}`);
27
+ const UNWRAP_NAMES = new Set([
28
+ 'unwrap',
29
+ 'unwrapErr',
30
+ 'expect',
31
+ 'expectErr'
32
+ ]);
33
+ const DEFAULT_MODULES = [
34
+ 'nalloc',
35
+ 'nalloc/safe',
36
+ 'nalloc/unsafe',
37
+ 'nalloc/result',
38
+ 'nalloc/option'
39
+ ];
40
+ const DEFAULT_TYPE_NAMES = [
41
+ 'Result',
42
+ 'Ok',
43
+ 'Err',
44
+ 'Option',
45
+ 'Some',
46
+ 'None'
47
+ ];
48
+ function nallocTypeName(type, names) {
49
+ const direct = type.aliasSymbol?.getName();
50
+ if (direct !== undefined && names.has(direct)) {
51
+ return direct;
52
+ }
53
+ if (type.isUnion()) {
54
+ for (const member of type.types){
55
+ const name = member.aliasSymbol?.getName();
56
+ if (name !== undefined && names.has(name)) {
57
+ return name;
58
+ }
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+ const mustUse = createRule({
64
+ name: 'must-use',
65
+ meta: {
66
+ type: 'problem',
67
+ docs: {
68
+ description: 'Require Result and Option values to be handled instead of silently discarded',
69
+ requiresTypeChecking: true
70
+ },
71
+ messages: {
72
+ mustUse: 'This {{name}} value is discarded. Handle it with match/unwrapOr/isErr/isNone, return it, or assign it.'
73
+ },
74
+ schema: [
75
+ {
76
+ type: 'object',
77
+ properties: {
78
+ typeNames: {
79
+ type: 'array',
80
+ items: {
81
+ type: 'string'
82
+ },
83
+ uniqueItems: true
84
+ }
85
+ },
86
+ additionalProperties: false
87
+ }
88
+ ],
89
+ defaultOptions: [
90
+ {}
91
+ ]
92
+ },
93
+ create (context, [options]) {
94
+ const names = new Set(options.typeNames ?? DEFAULT_TYPE_NAMES);
95
+ const services = _utils.ESLintUtils.getParserServices(context);
96
+ const check = (node)=>{
97
+ const name = nallocTypeName(services.getTypeAtLocation(node), names);
98
+ if (name !== undefined) {
99
+ context.report({
100
+ node,
101
+ messageId: 'mustUse',
102
+ data: {
103
+ name
104
+ }
105
+ });
106
+ }
107
+ };
108
+ return {
109
+ 'ExpressionStatement > CallExpression' (node) {
110
+ check(node);
111
+ },
112
+ 'ExpressionStatement > AwaitExpression' (node) {
113
+ check(node);
114
+ }
115
+ };
116
+ }
117
+ });
118
+ const noUnwrap = createRule({
119
+ name: 'no-unwrap',
120
+ meta: {
121
+ type: 'suggestion',
122
+ docs: {
123
+ description: 'Disallow unwrap and expect on Result and Option, which throw on failure'
124
+ },
125
+ messages: {
126
+ noUnwrap: '{{name}} throws on failure. Handle the error with match/unwrapOr/isErr, or turn this rule off in test files.'
127
+ },
128
+ schema: [
129
+ {
130
+ type: 'object',
131
+ properties: {
132
+ modules: {
133
+ type: 'array',
134
+ items: {
135
+ type: 'string'
136
+ },
137
+ uniqueItems: true
138
+ }
139
+ },
140
+ additionalProperties: false
141
+ }
142
+ ],
143
+ defaultOptions: [
144
+ {}
145
+ ]
146
+ },
147
+ create (context, [options]) {
148
+ const modules = new Set(options.modules ?? DEFAULT_MODULES);
149
+ const namespaceLocals = new Set();
150
+ const directLocals = new Map();
151
+ return {
152
+ ImportDeclaration (node) {
153
+ if (typeof node.source.value !== 'string' || !modules.has(node.source.value)) {
154
+ return;
155
+ }
156
+ for (const spec of node.specifiers){
157
+ if (spec.type === 'ImportNamespaceSpecifier') {
158
+ namespaceLocals.add(spec.local.name);
159
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
160
+ const imported = spec.imported.name;
161
+ if (imported === 'Result' || imported === 'Option') {
162
+ namespaceLocals.add(spec.local.name);
163
+ } else if (UNWRAP_NAMES.has(imported)) {
164
+ directLocals.set(spec.local.name, imported);
165
+ }
166
+ }
167
+ }
168
+ },
169
+ CallExpression (node) {
170
+ const callee = node.callee;
171
+ if (callee.type === 'MemberExpression' && !callee.computed && callee.property.type === 'Identifier' && callee.object.type === 'Identifier') {
172
+ if (UNWRAP_NAMES.has(callee.property.name) && namespaceLocals.has(callee.object.name)) {
173
+ context.report({
174
+ node: callee,
175
+ messageId: 'noUnwrap',
176
+ data: {
177
+ name: callee.property.name
178
+ }
179
+ });
180
+ }
181
+ return;
182
+ }
183
+ if (callee.type === 'Identifier') {
184
+ const imported = directLocals.get(callee.name);
185
+ if (imported !== undefined) {
186
+ context.report({
187
+ node: callee,
188
+ messageId: 'noUnwrap',
189
+ data: {
190
+ name: imported
191
+ }
192
+ });
193
+ }
194
+ }
195
+ }
196
+ };
197
+ }
198
+ });
199
+ const rules = {
200
+ 'must-use': mustUse,
201
+ 'no-unwrap': noUnwrap
202
+ };
203
+ const plugin = {
204
+ meta: {
205
+ name: 'nalloc'
206
+ },
207
+ rules,
208
+ configs: {}
209
+ };
210
+ plugin.configs.recommended = {
211
+ plugins: {
212
+ nalloc: plugin
213
+ },
214
+ rules: {
215
+ 'nalloc/must-use': 'error',
216
+ 'nalloc/no-unwrap': 'error'
217
+ }
218
+ };
219
+ const _default = plugin;
220
+
221
+ //# sourceMappingURL=eslint.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/eslint.ts"],"sourcesContent":["import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';\nimport type * as ts from 'typescript';\n\ninterface RuleDocs {\n description: string;\n requiresTypeChecking?: boolean;\n}\n\nconst createRule = ESLintUtils.RuleCreator<RuleDocs>((name) => `https://github.com/3axap4eHko/nalloc#${name}`);\n\nconst UNWRAP_NAMES: ReadonlySet<string> = new Set(['unwrap', 'unwrapErr', 'expect', 'expectErr']);\nconst DEFAULT_MODULES: readonly string[] = ['nalloc', 'nalloc/safe', 'nalloc/unsafe', 'nalloc/result', 'nalloc/option'];\nconst DEFAULT_TYPE_NAMES: readonly string[] = ['Result', 'Ok', 'Err', 'Option', 'Some', 'None'];\n\nfunction nallocTypeName(type: ts.Type, names: ReadonlySet<string>): string | undefined {\n const direct = type.aliasSymbol?.getName();\n if (direct !== undefined && names.has(direct)) {\n return direct;\n }\n if (type.isUnion()) {\n for (const member of type.types) {\n const name = member.aliasSymbol?.getName();\n if (name !== undefined && names.has(name)) {\n return name;\n }\n }\n }\n return undefined;\n}\n\nconst mustUse = createRule<[{ typeNames?: string[] }], 'mustUse'>({\n name: 'must-use',\n meta: {\n type: 'problem',\n docs: {\n description: 'Require Result and Option values to be handled instead of silently discarded',\n requiresTypeChecking: true,\n },\n messages: {\n mustUse: 'This {{name}} value is discarded. Handle it with match/unwrapOr/isErr/isNone, return it, or assign it.',\n },\n schema: [\n {\n type: 'object',\n properties: { typeNames: { type: 'array', items: { type: 'string' }, uniqueItems: true } },\n additionalProperties: false,\n },\n ],\n defaultOptions: [{}],\n },\n create(context, [options]) {\n const names = new Set(options.typeNames ?? DEFAULT_TYPE_NAMES);\n const services = ESLintUtils.getParserServices(context);\n const check = (node: TSESTree.Expression): void => {\n const name = nallocTypeName(services.getTypeAtLocation(node), names);\n if (name !== undefined) {\n context.report({ node, messageId: 'mustUse', data: { name } });\n }\n };\n return {\n 'ExpressionStatement > CallExpression'(node: TSESTree.CallExpression): void {\n check(node);\n },\n 'ExpressionStatement > AwaitExpression'(node: TSESTree.AwaitExpression): void {\n check(node);\n },\n };\n },\n});\n\nconst noUnwrap = createRule<[{ modules?: string[] }], 'noUnwrap'>({\n name: 'no-unwrap',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Disallow unwrap and expect on Result and Option, which throw on failure',\n },\n messages: {\n noUnwrap: '{{name}} throws on failure. Handle the error with match/unwrapOr/isErr, or turn this rule off in test files.',\n },\n schema: [\n {\n type: 'object',\n properties: { modules: { type: 'array', items: { type: 'string' }, uniqueItems: true } },\n additionalProperties: false,\n },\n ],\n defaultOptions: [{}],\n },\n create(context, [options]) {\n const modules = new Set(options.modules ?? DEFAULT_MODULES);\n const namespaceLocals = new Set<string>();\n const directLocals = new Map<string, string>();\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration): void {\n if (typeof node.source.value !== 'string' || !modules.has(node.source.value)) {\n return;\n }\n for (const spec of node.specifiers) {\n if (spec.type === 'ImportNamespaceSpecifier') {\n namespaceLocals.add(spec.local.name);\n } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {\n const imported = spec.imported.name;\n if (imported === 'Result' || imported === 'Option') {\n namespaceLocals.add(spec.local.name);\n } else if (UNWRAP_NAMES.has(imported)) {\n directLocals.set(spec.local.name, imported);\n }\n }\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n const callee = node.callee;\n if (callee.type === 'MemberExpression' && !callee.computed && callee.property.type === 'Identifier' && callee.object.type === 'Identifier') {\n if (UNWRAP_NAMES.has(callee.property.name) && namespaceLocals.has(callee.object.name)) {\n context.report({ node: callee, messageId: 'noUnwrap', data: { name: callee.property.name } });\n }\n return;\n }\n if (callee.type === 'Identifier') {\n const imported = directLocals.get(callee.name);\n if (imported !== undefined) {\n context.report({ node: callee, messageId: 'noUnwrap', data: { name: imported } });\n }\n }\n },\n };\n },\n});\n\nexport const rules = { 'must-use': mustUse, 'no-unwrap': noUnwrap };\n\nconst plugin: { meta: { name: string }; rules: typeof rules; configs: Record<string, unknown> } = {\n meta: { name: 'nalloc' },\n rules,\n configs: {},\n};\n\nplugin.configs.recommended = {\n plugins: { nalloc: plugin },\n rules: { 'nalloc/must-use': 'error', 'nalloc/no-unwrap': 'error' },\n};\n\nexport { mustUse, noUnwrap };\nexport default plugin;\n"],"names":["mustUse","noUnwrap","rules","createRule","ESLintUtils","RuleCreator","name","UNWRAP_NAMES","Set","DEFAULT_MODULES","DEFAULT_TYPE_NAMES","nallocTypeName","type","names","direct","aliasSymbol","getName","undefined","has","isUnion","member","types","meta","docs","description","requiresTypeChecking","messages","schema","properties","typeNames","items","uniqueItems","additionalProperties","defaultOptions","create","context","options","services","getParserServices","check","node","getTypeAtLocation","report","messageId","data","modules","namespaceLocals","directLocals","Map","ImportDeclaration","source","value","spec","specifiers","add","local","imported","set","CallExpression","callee","computed","property","object","get","plugin","configs","recommended","plugins","nalloc"],"mappings":";;;;;;;;;;;QAgJA;eAAA;;QADSA;eAAAA;;QAASC;eAAAA;;QAbLC;eAAAA;;;uBAlI8B;AAQ3C,MAAMC,aAAaC,kBAAW,CAACC,WAAW,CAAW,CAACC,OAAS,CAAC,qCAAqC,EAAEA,MAAM;AAE7G,MAAMC,eAAoC,IAAIC,IAAI;IAAC;IAAU;IAAa;IAAU;CAAY;AAChG,MAAMC,kBAAqC;IAAC;IAAU;IAAe;IAAiB;IAAiB;CAAgB;AACvH,MAAMC,qBAAwC;IAAC;IAAU;IAAM;IAAO;IAAU;IAAQ;CAAO;AAE/F,SAASC,eAAeC,IAAa,EAAEC,KAA0B;IAC/D,MAAMC,SAASF,KAAKG,WAAW,EAAEC;IACjC,IAAIF,WAAWG,aAAaJ,MAAMK,GAAG,CAACJ,SAAS;QAC7C,OAAOA;IACT;IACA,IAAIF,KAAKO,OAAO,IAAI;QAClB,KAAK,MAAMC,UAAUR,KAAKS,KAAK,CAAE;YAC/B,MAAMf,OAAOc,OAAOL,WAAW,EAAEC;YACjC,IAAIV,SAASW,aAAaJ,MAAMK,GAAG,CAACZ,OAAO;gBACzC,OAAOA;YACT;QACF;IACF;IACA,OAAOW;AACT;AAEA,MAAMjB,UAAUG,WAAkD;IAChEG,MAAM;IACNgB,MAAM;QACJV,MAAM;QACNW,MAAM;YACJC,aAAa;YACbC,sBAAsB;QACxB;QACAC,UAAU;YACR1B,SAAS;QACX;QACA2B,QAAQ;YACN;gBACEf,MAAM;gBACNgB,YAAY;oBAAEC,WAAW;wBAAEjB,MAAM;wBAASkB,OAAO;4BAAElB,MAAM;wBAAS;wBAAGmB,aAAa;oBAAK;gBAAE;gBACzFC,sBAAsB;YACxB;SACD;QACDC,gBAAgB;YAAC,CAAC;SAAE;IACtB;IACAC,QAAOC,OAAO,EAAE,CAACC,QAAQ;QACvB,MAAMvB,QAAQ,IAAIL,IAAI4B,QAAQP,SAAS,IAAInB;QAC3C,MAAM2B,WAAWjC,kBAAW,CAACkC,iBAAiB,CAACH;QAC/C,MAAMI,QAAQ,CAACC;YACb,MAAMlC,OAAOK,eAAe0B,SAASI,iBAAiB,CAACD,OAAO3B;YAC9D,IAAIP,SAASW,WAAW;gBACtBkB,QAAQO,MAAM,CAAC;oBAAEF;oBAAMG,WAAW;oBAAWC,MAAM;wBAAEtC;oBAAK;gBAAE;YAC9D;QACF;QACA,OAAO;YACL,wCAAuCkC,IAA6B;gBAClED,MAAMC;YACR;YACA,yCAAwCA,IAA8B;gBACpED,MAAMC;YACR;QACF;IACF;AACF;AAEA,MAAMvC,WAAWE,WAAiD;IAChEG,MAAM;IACNgB,MAAM;QACJV,MAAM;QACNW,MAAM;YACJC,aAAa;QACf;QACAE,UAAU;YACRzB,UAAU;QACZ;QACA0B,QAAQ;YACN;gBACEf,MAAM;gBACNgB,YAAY;oBAAEiB,SAAS;wBAAEjC,MAAM;wBAASkB,OAAO;4BAAElB,MAAM;wBAAS;wBAAGmB,aAAa;oBAAK;gBAAE;gBACvFC,sBAAsB;YACxB;SACD;QACDC,gBAAgB;YAAC,CAAC;SAAE;IACtB;IACAC,QAAOC,OAAO,EAAE,CAACC,QAAQ;QACvB,MAAMS,UAAU,IAAIrC,IAAI4B,QAAQS,OAAO,IAAIpC;QAC3C,MAAMqC,kBAAkB,IAAItC;QAC5B,MAAMuC,eAAe,IAAIC;QACzB,OAAO;YACLC,mBAAkBT,IAAgC;gBAChD,IAAI,OAAOA,KAAKU,MAAM,CAACC,KAAK,KAAK,YAAY,CAACN,QAAQ3B,GAAG,CAACsB,KAAKU,MAAM,CAACC,KAAK,GAAG;oBAC5E;gBACF;gBACA,KAAK,MAAMC,QAAQZ,KAAKa,UAAU,CAAE;oBAClC,IAAID,KAAKxC,IAAI,KAAK,4BAA4B;wBAC5CkC,gBAAgBQ,GAAG,CAACF,KAAKG,KAAK,CAACjD,IAAI;oBACrC,OAAO,IAAI8C,KAAKxC,IAAI,KAAK,qBAAqBwC,KAAKI,QAAQ,CAAC5C,IAAI,KAAK,cAAc;wBACjF,MAAM4C,WAAWJ,KAAKI,QAAQ,CAAClD,IAAI;wBACnC,IAAIkD,aAAa,YAAYA,aAAa,UAAU;4BAClDV,gBAAgBQ,GAAG,CAACF,KAAKG,KAAK,CAACjD,IAAI;wBACrC,OAAO,IAAIC,aAAaW,GAAG,CAACsC,WAAW;4BACrCT,aAAaU,GAAG,CAACL,KAAKG,KAAK,CAACjD,IAAI,EAAEkD;wBACpC;oBACF;gBACF;YACF;YACAE,gBAAelB,IAA6B;gBAC1C,MAAMmB,SAASnB,KAAKmB,MAAM;gBAC1B,IAAIA,OAAO/C,IAAI,KAAK,sBAAsB,CAAC+C,OAAOC,QAAQ,IAAID,OAAOE,QAAQ,CAACjD,IAAI,KAAK,gBAAgB+C,OAAOG,MAAM,CAAClD,IAAI,KAAK,cAAc;oBAC1I,IAAIL,aAAaW,GAAG,CAACyC,OAAOE,QAAQ,CAACvD,IAAI,KAAKwC,gBAAgB5B,GAAG,CAACyC,OAAOG,MAAM,CAACxD,IAAI,GAAG;wBACrF6B,QAAQO,MAAM,CAAC;4BAAEF,MAAMmB;4BAAQhB,WAAW;4BAAYC,MAAM;gCAAEtC,MAAMqD,OAAOE,QAAQ,CAACvD,IAAI;4BAAC;wBAAE;oBAC7F;oBACA;gBACF;gBACA,IAAIqD,OAAO/C,IAAI,KAAK,cAAc;oBAChC,MAAM4C,WAAWT,aAAagB,GAAG,CAACJ,OAAOrD,IAAI;oBAC7C,IAAIkD,aAAavC,WAAW;wBAC1BkB,QAAQO,MAAM,CAAC;4BAAEF,MAAMmB;4BAAQhB,WAAW;4BAAYC,MAAM;gCAAEtC,MAAMkD;4BAAS;wBAAE;oBACjF;gBACF;YACF;QACF;IACF;AACF;AAEO,MAAMtD,QAAQ;IAAE,YAAYF;IAAS,aAAaC;AAAS;AAElE,MAAM+D,SAA4F;IAChG1C,MAAM;QAAEhB,MAAM;IAAS;IACvBJ;IACA+D,SAAS,CAAC;AACZ;AAEAD,OAAOC,OAAO,CAACC,WAAW,GAAG;IAC3BC,SAAS;QAAEC,QAAQJ;IAAO;IAC1B9D,OAAO;QAAE,mBAAmB;QAAS,oBAAoB;IAAQ;AACnE;MAGA,WAAe8D"}
@@ -0,0 +1,36 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ interface RuleDocs {
3
+ description: string;
4
+ requiresTypeChecking?: boolean;
5
+ }
6
+ declare const mustUse: ESLintUtils.RuleModule<"mustUse", [{
7
+ typeNames?: string[];
8
+ }], RuleDocs, ESLintUtils.RuleListener> & {
9
+ name: string;
10
+ };
11
+ declare const noUnwrap: ESLintUtils.RuleModule<"noUnwrap", [{
12
+ modules?: string[];
13
+ }], RuleDocs, ESLintUtils.RuleListener> & {
14
+ name: string;
15
+ };
16
+ export declare const rules: {
17
+ 'must-use': ESLintUtils.RuleModule<"mustUse", [{
18
+ typeNames?: string[];
19
+ }], RuleDocs, ESLintUtils.RuleListener> & {
20
+ name: string;
21
+ };
22
+ 'no-unwrap': ESLintUtils.RuleModule<"noUnwrap", [{
23
+ modules?: string[];
24
+ }], RuleDocs, ESLintUtils.RuleListener> & {
25
+ name: string;
26
+ };
27
+ };
28
+ declare const plugin: {
29
+ meta: {
30
+ name: string;
31
+ };
32
+ rules: typeof rules;
33
+ configs: Record<string, unknown>;
34
+ };
35
+ export { mustUse, noUnwrap };
36
+ export default plugin;
@@ -0,0 +1,198 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ const createRule = ESLintUtils.RuleCreator((name)=>`https://github.com/3axap4eHko/nalloc#${name}`);
3
+ const UNWRAP_NAMES = new Set([
4
+ 'unwrap',
5
+ 'unwrapErr',
6
+ 'expect',
7
+ 'expectErr'
8
+ ]);
9
+ const DEFAULT_MODULES = [
10
+ 'nalloc',
11
+ 'nalloc/safe',
12
+ 'nalloc/unsafe',
13
+ 'nalloc/result',
14
+ 'nalloc/option'
15
+ ];
16
+ const DEFAULT_TYPE_NAMES = [
17
+ 'Result',
18
+ 'Ok',
19
+ 'Err',
20
+ 'Option',
21
+ 'Some',
22
+ 'None'
23
+ ];
24
+ function nallocTypeName(type, names) {
25
+ const direct = type.aliasSymbol?.getName();
26
+ if (direct !== undefined && names.has(direct)) {
27
+ return direct;
28
+ }
29
+ if (type.isUnion()) {
30
+ for (const member of type.types){
31
+ const name = member.aliasSymbol?.getName();
32
+ if (name !== undefined && names.has(name)) {
33
+ return name;
34
+ }
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ const mustUse = createRule({
40
+ name: 'must-use',
41
+ meta: {
42
+ type: 'problem',
43
+ docs: {
44
+ description: 'Require Result and Option values to be handled instead of silently discarded',
45
+ requiresTypeChecking: true
46
+ },
47
+ messages: {
48
+ mustUse: 'This {{name}} value is discarded. Handle it with match/unwrapOr/isErr/isNone, return it, or assign it.'
49
+ },
50
+ schema: [
51
+ {
52
+ type: 'object',
53
+ properties: {
54
+ typeNames: {
55
+ type: 'array',
56
+ items: {
57
+ type: 'string'
58
+ },
59
+ uniqueItems: true
60
+ }
61
+ },
62
+ additionalProperties: false
63
+ }
64
+ ],
65
+ defaultOptions: [
66
+ {}
67
+ ]
68
+ },
69
+ create (context, [options]) {
70
+ const names = new Set(options.typeNames ?? DEFAULT_TYPE_NAMES);
71
+ const services = ESLintUtils.getParserServices(context);
72
+ const check = (node)=>{
73
+ const name = nallocTypeName(services.getTypeAtLocation(node), names);
74
+ if (name !== undefined) {
75
+ context.report({
76
+ node,
77
+ messageId: 'mustUse',
78
+ data: {
79
+ name
80
+ }
81
+ });
82
+ }
83
+ };
84
+ return {
85
+ 'ExpressionStatement > CallExpression' (node) {
86
+ check(node);
87
+ },
88
+ 'ExpressionStatement > AwaitExpression' (node) {
89
+ check(node);
90
+ }
91
+ };
92
+ }
93
+ });
94
+ const noUnwrap = createRule({
95
+ name: 'no-unwrap',
96
+ meta: {
97
+ type: 'suggestion',
98
+ docs: {
99
+ description: 'Disallow unwrap and expect on Result and Option, which throw on failure'
100
+ },
101
+ messages: {
102
+ noUnwrap: '{{name}} throws on failure. Handle the error with match/unwrapOr/isErr, or turn this rule off in test files.'
103
+ },
104
+ schema: [
105
+ {
106
+ type: 'object',
107
+ properties: {
108
+ modules: {
109
+ type: 'array',
110
+ items: {
111
+ type: 'string'
112
+ },
113
+ uniqueItems: true
114
+ }
115
+ },
116
+ additionalProperties: false
117
+ }
118
+ ],
119
+ defaultOptions: [
120
+ {}
121
+ ]
122
+ },
123
+ create (context, [options]) {
124
+ const modules = new Set(options.modules ?? DEFAULT_MODULES);
125
+ const namespaceLocals = new Set();
126
+ const directLocals = new Map();
127
+ return {
128
+ ImportDeclaration (node) {
129
+ if (typeof node.source.value !== 'string' || !modules.has(node.source.value)) {
130
+ return;
131
+ }
132
+ for (const spec of node.specifiers){
133
+ if (spec.type === 'ImportNamespaceSpecifier') {
134
+ namespaceLocals.add(spec.local.name);
135
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
136
+ const imported = spec.imported.name;
137
+ if (imported === 'Result' || imported === 'Option') {
138
+ namespaceLocals.add(spec.local.name);
139
+ } else if (UNWRAP_NAMES.has(imported)) {
140
+ directLocals.set(spec.local.name, imported);
141
+ }
142
+ }
143
+ }
144
+ },
145
+ CallExpression (node) {
146
+ const callee = node.callee;
147
+ if (callee.type === 'MemberExpression' && !callee.computed && callee.property.type === 'Identifier' && callee.object.type === 'Identifier') {
148
+ if (UNWRAP_NAMES.has(callee.property.name) && namespaceLocals.has(callee.object.name)) {
149
+ context.report({
150
+ node: callee,
151
+ messageId: 'noUnwrap',
152
+ data: {
153
+ name: callee.property.name
154
+ }
155
+ });
156
+ }
157
+ return;
158
+ }
159
+ if (callee.type === 'Identifier') {
160
+ const imported = directLocals.get(callee.name);
161
+ if (imported !== undefined) {
162
+ context.report({
163
+ node: callee,
164
+ messageId: 'noUnwrap',
165
+ data: {
166
+ name: imported
167
+ }
168
+ });
169
+ }
170
+ }
171
+ }
172
+ };
173
+ }
174
+ });
175
+ export const rules = {
176
+ 'must-use': mustUse,
177
+ 'no-unwrap': noUnwrap
178
+ };
179
+ const plugin = {
180
+ meta: {
181
+ name: 'nalloc'
182
+ },
183
+ rules,
184
+ configs: {}
185
+ };
186
+ plugin.configs.recommended = {
187
+ plugins: {
188
+ nalloc: plugin
189
+ },
190
+ rules: {
191
+ 'nalloc/must-use': 'error',
192
+ 'nalloc/no-unwrap': 'error'
193
+ }
194
+ };
195
+ export { mustUse, noUnwrap };
196
+ export default plugin;
197
+
198
+ //# sourceMappingURL=eslint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/eslint.ts"],"sourcesContent":["import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';\nimport type * as ts from 'typescript';\n\ninterface RuleDocs {\n description: string;\n requiresTypeChecking?: boolean;\n}\n\nconst createRule = ESLintUtils.RuleCreator<RuleDocs>((name) => `https://github.com/3axap4eHko/nalloc#${name}`);\n\nconst UNWRAP_NAMES: ReadonlySet<string> = new Set(['unwrap', 'unwrapErr', 'expect', 'expectErr']);\nconst DEFAULT_MODULES: readonly string[] = ['nalloc', 'nalloc/safe', 'nalloc/unsafe', 'nalloc/result', 'nalloc/option'];\nconst DEFAULT_TYPE_NAMES: readonly string[] = ['Result', 'Ok', 'Err', 'Option', 'Some', 'None'];\n\nfunction nallocTypeName(type: ts.Type, names: ReadonlySet<string>): string | undefined {\n const direct = type.aliasSymbol?.getName();\n if (direct !== undefined && names.has(direct)) {\n return direct;\n }\n if (type.isUnion()) {\n for (const member of type.types) {\n const name = member.aliasSymbol?.getName();\n if (name !== undefined && names.has(name)) {\n return name;\n }\n }\n }\n return undefined;\n}\n\nconst mustUse = createRule<[{ typeNames?: string[] }], 'mustUse'>({\n name: 'must-use',\n meta: {\n type: 'problem',\n docs: {\n description: 'Require Result and Option values to be handled instead of silently discarded',\n requiresTypeChecking: true,\n },\n messages: {\n mustUse: 'This {{name}} value is discarded. Handle it with match/unwrapOr/isErr/isNone, return it, or assign it.',\n },\n schema: [\n {\n type: 'object',\n properties: { typeNames: { type: 'array', items: { type: 'string' }, uniqueItems: true } },\n additionalProperties: false,\n },\n ],\n defaultOptions: [{}],\n },\n create(context, [options]) {\n const names = new Set(options.typeNames ?? DEFAULT_TYPE_NAMES);\n const services = ESLintUtils.getParserServices(context);\n const check = (node: TSESTree.Expression): void => {\n const name = nallocTypeName(services.getTypeAtLocation(node), names);\n if (name !== undefined) {\n context.report({ node, messageId: 'mustUse', data: { name } });\n }\n };\n return {\n 'ExpressionStatement > CallExpression'(node: TSESTree.CallExpression): void {\n check(node);\n },\n 'ExpressionStatement > AwaitExpression'(node: TSESTree.AwaitExpression): void {\n check(node);\n },\n };\n },\n});\n\nconst noUnwrap = createRule<[{ modules?: string[] }], 'noUnwrap'>({\n name: 'no-unwrap',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Disallow unwrap and expect on Result and Option, which throw on failure',\n },\n messages: {\n noUnwrap: '{{name}} throws on failure. Handle the error with match/unwrapOr/isErr, or turn this rule off in test files.',\n },\n schema: [\n {\n type: 'object',\n properties: { modules: { type: 'array', items: { type: 'string' }, uniqueItems: true } },\n additionalProperties: false,\n },\n ],\n defaultOptions: [{}],\n },\n create(context, [options]) {\n const modules = new Set(options.modules ?? DEFAULT_MODULES);\n const namespaceLocals = new Set<string>();\n const directLocals = new Map<string, string>();\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration): void {\n if (typeof node.source.value !== 'string' || !modules.has(node.source.value)) {\n return;\n }\n for (const spec of node.specifiers) {\n if (spec.type === 'ImportNamespaceSpecifier') {\n namespaceLocals.add(spec.local.name);\n } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {\n const imported = spec.imported.name;\n if (imported === 'Result' || imported === 'Option') {\n namespaceLocals.add(spec.local.name);\n } else if (UNWRAP_NAMES.has(imported)) {\n directLocals.set(spec.local.name, imported);\n }\n }\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n const callee = node.callee;\n if (callee.type === 'MemberExpression' && !callee.computed && callee.property.type === 'Identifier' && callee.object.type === 'Identifier') {\n if (UNWRAP_NAMES.has(callee.property.name) && namespaceLocals.has(callee.object.name)) {\n context.report({ node: callee, messageId: 'noUnwrap', data: { name: callee.property.name } });\n }\n return;\n }\n if (callee.type === 'Identifier') {\n const imported = directLocals.get(callee.name);\n if (imported !== undefined) {\n context.report({ node: callee, messageId: 'noUnwrap', data: { name: imported } });\n }\n }\n },\n };\n },\n});\n\nexport const rules = { 'must-use': mustUse, 'no-unwrap': noUnwrap };\n\nconst plugin: { meta: { name: string }; rules: typeof rules; configs: Record<string, unknown> } = {\n meta: { name: 'nalloc' },\n rules,\n configs: {},\n};\n\nplugin.configs.recommended = {\n plugins: { nalloc: plugin },\n rules: { 'nalloc/must-use': 'error', 'nalloc/no-unwrap': 'error' },\n};\n\nexport { mustUse, noUnwrap };\nexport default plugin;\n"],"names":["ESLintUtils","createRule","RuleCreator","name","UNWRAP_NAMES","Set","DEFAULT_MODULES","DEFAULT_TYPE_NAMES","nallocTypeName","type","names","direct","aliasSymbol","getName","undefined","has","isUnion","member","types","mustUse","meta","docs","description","requiresTypeChecking","messages","schema","properties","typeNames","items","uniqueItems","additionalProperties","defaultOptions","create","context","options","services","getParserServices","check","node","getTypeAtLocation","report","messageId","data","noUnwrap","modules","namespaceLocals","directLocals","Map","ImportDeclaration","source","value","spec","specifiers","add","local","imported","set","CallExpression","callee","computed","property","object","get","rules","plugin","configs","recommended","plugins","nalloc"],"mappings":"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"}
package/build/http.cjs ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get fromFetch () {
13
+ return fromFetch;
14
+ },
15
+ get fromResponse () {
16
+ return fromResponse;
17
+ }
18
+ });
19
+ const _typescjs = require("./types.cjs");
20
+ function fromResponse(response) {
21
+ return response.ok ? response : (0, _typescjs.err)(response);
22
+ }
23
+ async function fromFetch(input, init) {
24
+ try {
25
+ return fromResponse(await fetch(input, init));
26
+ } catch (error) {
27
+ return (0, _typescjs.err)(error);
28
+ }
29
+ }
30
+
31
+ //# sourceMappingURL=http.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http.ts"],"sourcesContent":["import { err as ERR } from './types.js';\nimport type { Ok, Result } from './types.js';\n\n/**\n * Converts a fetch Response into a Result, treating a non-ok status as an Err.\n * Native fetch only rejects on transport errors, never on 4xx/5xx; this closes that gap.\n * The failed Response itself is the error - read its status, headers, or body from it.\n * @param response - The Response to inspect\n * @returns Ok(response) when response.ok, Err(response) otherwise\n * @example\n * import { Result } from 'nalloc';\n * import { fromResponse } from 'nalloc/http';\n * const res = Result.flatMap(await Result.fromPromise(fetch(url)), fromResponse);\n */\nexport function fromResponse(response: Response): Result<Response, Response> {\n return response.ok ? (response as Ok<Response>) : ERR(response);\n}\n\n/**\n * Runs fetch and forces every failure mode into the error channel.\n * Ok means the request connected AND returned a 2xx status; a non-2xx Response\n * becomes Err(response), and a transport failure becomes Err with the thrown\n * value (per spec: TypeError on network/CORS errors, DOMException on abort/timeout).\n * The body is never read - it stays available to the caller.\n * @param input - The fetch input (URL or Request)\n * @param init - Optional fetch init\n * @returns Promise of Ok(response) for 2xx, Err otherwise\n * @example\n * import { fromFetch } from 'nalloc/http';\n * const res = await fromFetch(url);\n * // Ok(Response) -> connected and 2xx\n * // Err(Response) -> reached the server, non-2xx\n * // Err(TypeError) -> network/CORS failure\n * // Err(DOMException) -> aborted or timed out\n */\nexport async function fromFetch(input: string | URL | Request, init?: RequestInit): Promise<Result<Response, Response | TypeError | DOMException>> {\n try {\n return fromResponse(await fetch(input, init));\n } catch (error) {\n return ERR(error as TypeError | DOMException);\n }\n}\n"],"names":["fromFetch","fromResponse","response","ok","ERR","input","init","fetch","error"],"mappings":";;;;;;;;;;;QAmCsBA;eAAAA;;QArBNC;eAAAA;;;0BAdW;AAcpB,SAASA,aAAaC,QAAkB;IAC7C,OAAOA,SAASC,EAAE,GAAID,WAA4BE,IAAAA,aAAG,EAACF;AACxD;AAmBO,eAAeF,UAAUK,KAA6B,EAAEC,IAAkB;IAC/E,IAAI;QACF,OAAOL,aAAa,MAAMM,MAAMF,OAAOC;IACzC,EAAE,OAAOE,OAAO;QACd,OAAOJ,IAAAA,aAAG,EAACI;IACb;AACF"}