tyfigo 0.2.0-next.a30eb96.0 → 0.2.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 (68) hide show
  1. package/README.md +28 -4
  2. package/dist/bun.d.mts +8 -1
  3. package/dist/bun.mjs +7 -7
  4. package/dist/bun.mjs.map +1 -1
  5. package/dist/effect.mjs +2 -2
  6. package/dist/{env-Bd-1Atoz.mjs → env--pSRlq_k.mjs} +2 -2
  7. package/dist/{env-Bd-1Atoz.mjs.map → env--pSRlq_k.mjs.map} +1 -1
  8. package/dist/env-Dv5OHfEf.mjs +51 -0
  9. package/dist/env-Dv5OHfEf.mjs.map +1 -0
  10. package/dist/{formats-D_dKXoPf.mjs → formats-Bf8-iQw-.mjs} +43 -15
  11. package/dist/{formats-D_dKXoPf.mjs.map → formats-Bf8-iQw-.mjs.map} +1 -1
  12. package/dist/index.mjs +1 -1
  13. package/dist/{load-C-kweoyY.d.mts → load-D1KO5LdK.d.mts} +6 -4
  14. package/dist/{load-DxIjRpX6.mjs → load-yFCdP4to.mjs} +49 -23
  15. package/dist/load-yFCdP4to.mjs.map +1 -0
  16. package/dist/mapper.mjs +28 -11
  17. package/dist/mapper.mjs.map +1 -1
  18. package/dist/plugins/esbuild.d.mts +2 -2
  19. package/dist/plugins/esbuild.mjs +1 -1
  20. package/dist/plugins/jest.d.mts +1 -1
  21. package/dist/plugins/jest.mjs +4 -4
  22. package/dist/plugins/loader.d.mts +1 -1
  23. package/dist/plugins/loader.mjs +3 -2
  24. package/dist/plugins/loader.mjs.map +1 -1
  25. package/dist/plugins/next.d.mts +1 -1
  26. package/dist/plugins/next.mjs +9 -4
  27. package/dist/plugins/next.mjs.map +1 -1
  28. package/dist/plugins/rolldown.d.mts +2 -2
  29. package/dist/plugins/rolldown.mjs +1 -1
  30. package/dist/plugins/rollup.d.mts +2 -2
  31. package/dist/plugins/rollup.mjs +1 -1
  32. package/dist/plugins/rsbuild.d.mts +2 -2
  33. package/dist/plugins/rsbuild.mjs +1 -1
  34. package/dist/plugins/rspack.d.mts +2 -2
  35. package/dist/plugins/rspack.mjs +1 -1
  36. package/dist/plugins/vite.d.mts +2 -2
  37. package/dist/plugins/vite.mjs +1 -1
  38. package/dist/plugins/webpack.d.mts +2 -2
  39. package/dist/plugins/webpack.mjs +1 -1
  40. package/dist/problems-DS_eJB6e.mjs +86 -0
  41. package/dist/problems-DS_eJB6e.mjs.map +1 -0
  42. package/dist/register.mjs +5 -5
  43. package/dist/register.mjs.map +1 -1
  44. package/dist/{resolve-D3geHCGs.mjs → resolve-DQfTdYJN.mjs} +32 -12
  45. package/dist/resolve-DQfTdYJN.mjs.map +1 -0
  46. package/dist/runtime/index.d.mts +13 -4
  47. package/dist/runtime/index.mjs +2 -2
  48. package/dist/{runtime-DeRUtPZ9.mjs → runtime-B3GmIYop.mjs} +13 -9
  49. package/dist/runtime-B3GmIYop.mjs.map +1 -0
  50. package/dist/{shared-CZ44uwQq.d.mts → shared-B6Y3_kdn.d.mts} +6 -5
  51. package/dist/{shared-BnK77Zcp.mjs → shared-DOMPQnVO.mjs} +4 -6
  52. package/dist/shared-DOMPQnVO.mjs.map +1 -0
  53. package/dist/{sync-B-HAK-_E.mjs → sync-mWkXcCOW.mjs} +2 -2
  54. package/dist/{sync-B-HAK-_E.mjs.map → sync-mWkXcCOW.mjs.map} +1 -1
  55. package/dist/unplugin-BYfqHkIE.d.mts +2 -0
  56. package/dist/{unplugin-BQGm_bhA.mjs → unplugin-Bkc569Qw.mjs} +10 -8
  57. package/dist/unplugin-Bkc569Qw.mjs.map +1 -0
  58. package/package.json +1 -1
  59. package/dist/env-R3_XPW_u.mjs +0 -78
  60. package/dist/env-R3_XPW_u.mjs.map +0 -1
  61. package/dist/load-DxIjRpX6.mjs.map +0 -1
  62. package/dist/problems-BNAqmOzL.mjs +0 -23
  63. package/dist/problems-BNAqmOzL.mjs.map +0 -1
  64. package/dist/resolve-D3geHCGs.mjs.map +0 -1
  65. package/dist/runtime-DeRUtPZ9.mjs.map +0 -1
  66. package/dist/shared-BnK77Zcp.mjs.map +0 -1
  67. package/dist/unplugin-AC_HM_T2.d.mts +0 -2
  68. package/dist/unplugin-BQGm_bhA.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mapper.mjs","names":[],"sources":["../src/mapper/rpc.ts","../src/mapper/generate.ts","../src/mapper/server.ts","../src/mapper.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\n\nimport type { Readable, Writable } from 'node:stream';\n\nexport type RequestId = number | string | null;\n\nexport interface RpcMessage {\n\treadonly jsonrpc: '2.0';\n\treadonly id?: RequestId;\n\treadonly method?: string;\n\treadonly params?: unknown;\n}\n\nexport class RpcError extends Error {\n\treadonly code: number;\n\n\tconstructor(code: number, message: string) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\nexport const RpcErrorCode = {\n\tParseError: -32_700,\n\tInvalidRequest: -32_600,\n\tMethodNotFound: -32_601,\n\tInvalidParams: -32_602,\n\tInternalError: -32_603,\n} as const;\n\n/**\n * Handles one request or notification and returns its result.\n */\nexport type RpcHandler = (method: string, params: unknown) => unknown;\n\nconst separator = Buffer.from('\\r\\n\\r\\n');\n\nexport const encodeMessage = (message: unknown): Buffer => {\n\tconst body = Buffer.from(JSON.stringify(message), 'utf8');\n\treturn Buffer.concat([Buffer.from(`Content-Length: ${body.length}\\r\\n\\r\\n`, 'ascii'), body]);\n};\n\n/**\n * Splits a stream of `Content-Length` framed chunks into message bodies.\n */\nexport class MessageReader {\n\t#buffer: Buffer = Buffer.alloc(0);\n\n\tpush(chunk: Buffer): string[] {\n\t\tthis.#buffer = Buffer.concat([this.#buffer, chunk]);\n\t\tconst bodies: string[] = [];\n\t\tfor (;;) {\n\t\t\tconst end = this.#buffer.indexOf(separator);\n\t\t\tif (end === -1) return bodies;\n\t\t\tconst header = this.#buffer.subarray(0, end).toString('ascii');\n\t\t\tconst match = /^content-length:\\s*(\\d+)\\s*$/imu.exec(header);\n\t\t\tif (!match) throw new RpcError(RpcErrorCode.ParseError, `Missing Content-Length in header: ${header}`);\n\t\t\tconst start = end + separator.length;\n\t\t\tconst length = Number(match[1]);\n\t\t\tif (this.#buffer.length < start + length) return bodies;\n\t\t\tbodies.push(this.#buffer.subarray(start, start + length).toString('utf8'));\n\t\t\tthis.#buffer = this.#buffer.subarray(start + length);\n\t\t}\n\t}\n}\n\nconst isMessage = (value: unknown): value is RpcMessage =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * The response to one message body, or `undefined` for a notification.\n */\nexport const dispatch = (body: string, handle: RpcHandler): object | undefined => {\n\tlet message: unknown;\n\ttry {\n\t\tmessage = JSON.parse(body);\n\t} catch (error) {\n\t\treturn { jsonrpc: '2.0', id: null, error: { code: RpcErrorCode.ParseError, message: String(error) } };\n\t}\n\n\tif (!isMessage(message) || typeof message.method !== 'string') {\n\t\tconst id = isMessage(message) ? (message.id ?? null) : null;\n\t\treturn { jsonrpc: '2.0', id, error: { code: RpcErrorCode.InvalidRequest, message: 'Invalid request' } };\n\t}\n\n\tconst isNotification = !('id' in message);\n\ttry {\n\t\tconst result = handle(message.method, message.params);\n\t\treturn isNotification ? undefined : { jsonrpc: '2.0', id: message.id ?? null, result: result ?? null };\n\t} catch (error) {\n\t\tif (isNotification) return undefined;\n\t\tconst code = error instanceof RpcError ? error.code : RpcErrorCode.InternalError;\n\t\tconst text = error instanceof Error ? error.message : String(error);\n\t\treturn { jsonrpc: '2.0', id: message.id ?? null, error: { code, message: text } };\n\t}\n};\n\n/**\n * Answers JSON-RPC 2.0 messages from `input` on `output` until `input` ends.\n */\nexport const serve = (handle: RpcHandler, input: Readable, output: Writable): Promise<void> =>\n\tnew Promise((resolve, reject) => {\n\t\tconst reader = new MessageReader();\n\t\tinput.on('data', (chunk: Buffer) => {\n\t\t\tlet bodies: string[];\n\t\t\ttry {\n\t\t\t\tbodies = reader.push(chunk);\n\t\t\t} catch (error) {\n\t\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const body of bodies) {\n\t\t\t\tconst response = dispatch(body, handle);\n\t\t\t\tif (response) output.write(encodeMessage(response));\n\t\t\t}\n\t\t});\n\t\tinput.once('end', () => resolve());\n\t\tinput.once('error', reject);\n\t});\n","import { Buffer } from 'node:buffer';\nimport { basename, dirname, relative, resolve } from 'node:path';\n\nimport { configSuffixes, parseConfigFileName } from '../core/formats/index.ts';\nimport { isPlainObject, resolvePlaceholders } from '../core/placeholders.ts';\nimport { pathKey, SourceIndex } from '../core/positions.ts';\nimport { fileProblem } from '../core/problems.ts';\n\nimport type { Format } from '../core/formats/index.ts';\nimport type { LayerKind } from '../core/layers.ts';\nimport type { Path, PositionMap } from '../core/positions.ts';\nimport type { Problem, ProblemCode } from '../core/problems.ts';\n\nexport const SpanMapKind = { Verbatim: 0, Atom: 1, Alias: 2 } as const;\nexport type SpanMapKind = (typeof SpanMapKind)[keyof typeof SpanMapKind];\n\n/**\n * `[virtualStart, virtualLength, originalStart, originalLength, kind]` in UTF-8 bytes.\n */\nexport type SpanMapping = readonly [\n\tvirtualStart: number,\n\tvirtualLength: number,\n\toriginalStart: number,\n\toriginalLength: number,\n\tkind: SpanMapKind,\n];\n\n/**\n * A problem in the original file. `start` and `length` are UTF-8 byte offsets.\n */\nexport interface MapperDiagnostic {\n\treadonly messageText: string;\n\treadonly start: number;\n\treadonly length: number;\n\treadonly code: number;\n}\n\nexport interface GeneratedModule {\n\treadonly text: string;\n\treadonly extension: '.ts';\n\treadonly mappings: readonly SpanMapping[];\n\treadonly diagnostics: readonly MapperDiagnostic[];\n}\n\nexport interface GenerateOptions {\n\t/**\n\t * The base config file this file layers on. Defaults to the name implied by `path` (`app.config.yaml` for\n\t * `app.production.config.yaml`). When it is `path` itself, `path` is generated as the base file.\n\t */\n\treadonly base?: string | undefined;\n}\n\nexport const diagnosticCodes: Readonly<Record<ProblemCode, number>> = {\n\t'parse-error': 1_001,\n\t'duplicate-key': 1_002,\n\t'file-not-found': 1_003,\n\t'read-error': 1_004,\n\t'unsupported-file': 1_005,\n\t'missing-variable': 1_006,\n\t'invalid-placeholder': 1_007,\n\t'unknown-key': 1_008,\n\t'type-mismatch': 1_009,\n\t'browser-placeholder': 1_010,\n\t'placeholder-type': 1_011,\n};\n\nexport interface ConfigFileRole {\n\treadonly kind: LayerKind;\n\t/**\n\t * The base file's name, `app.config.yaml` for `app.production.local.config.yaml`.\n\t */\n\treadonly base: string;\n\treadonly environment: string | undefined;\n\treadonly format: Format;\n}\n\n/**\n * Reads a config file's layer from its name: the first dot-separated part of the stem names the base file, a trailing `local`\n * marks a local file and anything in between is the environment.\n */\nexport const configFileRole = (fileName: string): ConfigFileRole | undefined => {\n\tconst name = parseConfigFileName(fileName);\n\tif (!name) return undefined;\n\tconst [stem = '', ...rest] = name.stem.split('.');\n\tconst base = `${stem}${name.suffix}`;\n\tconst isLocal = rest.at(-1) === 'local';\n\tconst environment = (isLocal ? rest.slice(0, -1) : rest).join('.') || undefined;\n\tconst kind: LayerKind = isLocal\n\t\t? environment\n\t\t\t? 'environment-local'\n\t\t\t: 'local'\n\t\t: environment\n\t\t\t? 'environment'\n\t\t\t: 'base';\n\treturn { kind, base, environment, format: name.format };\n};\n\nconst wholePlaceholder = /^\\$\\{[A-Za-z_]\\w*(?:(:-|:\\?)([^}]*))?\\}$/u;\n\nconst identifier = /^[A-Za-z_$][\\w$]*$/u;\n\nconst isStringLiteral = (text: string, value: string) =>\n\ttext === JSON.stringify(value) || (text === `'${value}'` && !/['\\\\\\n\\r\\u2028\\u2029]/u.test(value));\n\nconst numberLiteral = (value: number) =>\n\tNumber.isNaN(value) ? 'NaN' : Number.isFinite(value) ? String(value) : value > 0 ? 'Infinity' : '-Infinity';\n\nclass Writer {\n\ttext = '';\n\tbytes = 0;\n\treadonly mappings: SpanMapping[] = [];\n\n\twrite(text: string): this {\n\t\tthis.text += text;\n\t\tthis.bytes += Buffer.byteLength(text);\n\t\treturn this;\n\t}\n\n\tmap(text: string, start: number, length: number, kind: SpanMapKind): this {\n\t\tthis.mappings.push([this.bytes, Buffer.byteLength(text), start, length, kind]);\n\t\treturn this.write(text);\n\t}\n\n\tappend(other: Writer): this {\n\t\tfor (const [start, ...rest] of other.mappings) this.mappings.push([start + this.bytes, ...rest]);\n\t\treturn this.write(other.text);\n\t}\n}\n\nclass Generator {\n\treadonly source: SourceIndex;\n\treadonly positions: PositionMap;\n\treadonly format: Format;\n\n\tconstructor(text: string, positions: PositionMap, format: Format) {\n\t\tthis.source = new SourceIndex(text);\n\t\tthis.positions = positions;\n\t\tthis.format = format;\n\t}\n\n\t#slice(start: number, length: number) {\n\t\treturn this.source.text.slice(this.source.charIndex(start), this.source.charIndex(start + length));\n\t}\n\n\t#original(path: Path, part: 'key' | 'value') {\n\t\tconst span = this.positions.get(pathKey(path));\n\t\tif (!span) return undefined;\n\t\treturn part === 'key'\n\t\t\t? this.#slice(span.keyStart, span.keyLength)\n\t\t\t: this.#slice(span.valueStart, span.valueLength);\n\t}\n\n\t/**\n\t * Writes a property name, reusing the original spelling when it is valid TypeScript for the same key.\n\t */\n\tkey(writer: Writer, key: string, path: Path) {\n\t\tconst original = this.#original(path, 'key');\n\t\tconst text =\n\t\t\toriginal !== undefined && isStringLiteral(original, key)\n\t\t\t\t? original\n\t\t\t\t: identifier.test(key)\n\t\t\t\t\t? key\n\t\t\t\t\t: JSON.stringify(key);\n\t\treturn this.mapped(writer, text, path, 'key');\n\t}\n\n\tstring(value: string, path: Path) {\n\t\tconst original = this.#original(path, 'value');\n\t\treturn original !== undefined && isStringLiteral(original, value) ? original : JSON.stringify(value);\n\t}\n\n\t/**\n\t * Writes `text` mapped to the key or value of `path`: Verbatim when it is the original text, `fallback` otherwise.\n\t */\n\tmapped(writer: Writer, text: string, path: Path, part: 'key' | 'value', fallback: SpanMapKind = SpanMapKind.Alias) {\n\t\tconst span = this.positions.get(pathKey(path));\n\t\tif (!span) return writer.write(text);\n\t\tconst [start, length] = part === 'key' ? [span.keyStart, span.keyLength] : [span.valueStart, span.valueLength];\n\t\treturn writer.map(text, start, length, this.#slice(start, length) === text ? SpanMapKind.Verbatim : fallback);\n\t}\n\n\tplaceholderType(text: string) {\n\t\tconst match = wholePlaceholder.exec(text);\n\t\tif (match?.[1] !== ':-') return 'string';\n\t\tconst value = this.format.parseScalar(match[2] ?? '');\n\t\treturn value === null ? 'null' : typeof value;\n\t}\n\n\ttype(value: unknown, path: Path, indent: string): Writer {\n\t\tconst writer = new Writer();\n\t\tif (Array.isArray(value)) return this.#arrayType(value, path, indent);\n\t\tif (isPlainObject(value)) {\n\t\t\tconst entries = Object.entries(value);\n\t\t\tif (entries.length === 0) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\tthis.mapped(writer, '{', path, 'value', SpanMapKind.Atom).write('\\n');\n\t\t\tfor (const [key, item] of entries) {\n\t\t\t\tconst childPath = [...path, key];\n\t\t\t\twriter.write(`${indent}\\treadonly `);\n\t\t\t\tthis.key(writer, key, childPath);\n\t\t\t\twriter\n\t\t\t\t\t.write(': ')\n\t\t\t\t\t.append(this.type(item, childPath, `${indent}\\t`))\n\t\t\t\t\t.write(';\\n');\n\t\t\t}\n\t\t\treturn writer.write(`${indent}}`);\n\t\t}\n\n\t\tconst text =\n\t\t\tvalue === null\n\t\t\t\t? 'null'\n\t\t\t\t: typeof value === 'string'\n\t\t\t\t\t? this.placeholderType(value)\n\t\t\t\t\t: typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint'\n\t\t\t\t\t\t? typeof value\n\t\t\t\t\t\t: 'unknown';\n\t\treturn this.mapped(writer, text, path, 'value');\n\t}\n\n\t#arrayType(items: readonly unknown[], path: Path, indent: string) {\n\t\tconst members = new Map<string, Writer>();\n\t\tfor (const [index, item] of items.entries()) {\n\t\t\tconst member = this.type(item, [...path, index], indent);\n\t\t\tif (!members.has(member.text)) members.set(member.text, member);\n\t\t}\n\n\t\tconst writer = this.mapped(new Writer(), 'readonly', path, 'value', SpanMapKind.Atom).write(' ');\n\t\tif (members.size === 0) return writer.write('unknown[]');\n\t\tconst [first] = members.values();\n\t\tconst wrap = members.size > 1 || first?.text.startsWith('readonly');\n\t\tif (wrap) writer.write('(');\n\t\tfor (const [index, member] of [...members.values()].entries()) {\n\t\t\tif (index > 0) writer.write(' | ');\n\t\t\twriter.append(member);\n\t\t}\n\t\treturn writer.write(wrap ? ')[]' : '[]');\n\t}\n\n\t/**\n\t * An expression for `value`. Objects that are not inside an array become `{}` when `shallow` is set, because their keys are\n\t * checked by statements of their own.\n\t */\n\tvalue(value: unknown, path: Path, shallow: boolean): Writer {\n\t\tconst writer = new Writer();\n\t\tif (Array.isArray(value)) {\n\t\t\twriter.write('[');\n\t\t\tfor (const [index, item] of value.entries()) {\n\t\t\t\tif (index > 0) writer.write(', ');\n\t\t\t\twriter.append(this.value(item, [...path, index], false));\n\t\t\t}\n\t\t\treturn writer.write(']');\n\t\t}\n\n\t\tif (isPlainObject(value)) {\n\t\t\tif (shallow) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\tconst entries = Object.entries(value);\n\t\t\tif (entries.length === 0) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\twriter.write('{ ');\n\t\t\tfor (const [index, [key, item]] of entries.entries()) {\n\t\t\t\tconst childPath = [...path, key];\n\t\t\t\tif (index > 0) writer.write(', ');\n\t\t\t\tthis.key(writer, key, childPath);\n\t\t\t\twriter.write(': ').append(this.value(item, childPath, false));\n\t\t\t}\n\t\t\treturn writer.write(' }');\n\t\t}\n\n\t\tif (typeof value === 'string' && wholePlaceholder.test(value)) {\n\t\t\treturn this.mapped(writer, '(undefined as never)', path, 'value');\n\t\t}\n\n\t\tconst text =\n\t\t\tvalue === null || typeof value === 'boolean'\n\t\t\t\t? String(value)\n\t\t\t\t: typeof value === 'string'\n\t\t\t\t\t? this.string(value, path)\n\t\t\t\t\t: typeof value === 'number'\n\t\t\t\t\t\t? numberLiteral(value)\n\t\t\t\t\t\t: typeof value === 'bigint'\n\t\t\t\t\t\t\t? `${value}n`\n\t\t\t\t\t\t\t: '(undefined as never)';\n\t\treturn this.mapped(writer, text, path, 'value');\n\t}\n}\n\nconst toDiagnostic = (problem: Problem): MapperDiagnostic => ({\n\tmessageText: problem.message,\n\tstart: problem.start,\n\tlength: problem.length,\n\tcode: diagnosticCodes[problem.code],\n});\n\nconst untyped = (diagnostics: readonly MapperDiagnostic[]): GeneratedModule => ({\n\ttext: 'declare const config: any;\\nexport default config;\\n',\n\textension: '.ts',\n\tmappings: [],\n\tdiagnostics,\n});\n\nconst baseModule = (generator: Generator, value: unknown) =>\n\tnew Writer()\n\t\t.write('declare const config: ')\n\t\t.append(generator.type(value, [], ''))\n\t\t.write(';\\nexport default config;\\n');\n\nconst importSpecifier = (from: string, to: string) => {\n\tconst specifier = relative(dirname(from), to).replaceAll('\\\\', '/');\n\treturn specifier.startsWith('.') ? specifier : `./${specifier}`;\n};\n\nconst layerModule = (generator: Generator, value: unknown, specifier: string) => {\n\tconst statements = new Writer();\n\n\tconst visit = (object: Record<string, unknown>, path: Path, target: string): boolean => {\n\t\tlet nested = false;\n\t\tfor (const [key, item] of Object.entries(object)) {\n\t\t\tconst childPath = [...path, key];\n\t\t\tstatements.write('({ ');\n\t\t\tgenerator.key(statements, key, childPath);\n\t\t\tstatements.write(': ').append(generator.value(item, childPath, true));\n\t\t\tstatements.write(` }) satisfies Override<${target}>;\\n`);\n\t\t\tif (isPlainObject(item)) {\n\t\t\t\tnested = true;\n\t\t\t\tvisit(item, childPath, `At<${target}, ${JSON.stringify(key)}>`);\n\t\t\t}\n\t\t}\n\t\treturn nested;\n\t};\n\n\tlet usesAt = false;\n\tif (isPlainObject(value)) usesAt = visit(value, [], 'Config');\n\telse {\n\t\tstatements.write('(').append(generator.value(value, [], false));\n\t\tstatements.write(') ');\n\t\tgenerator.mapped(statements, 'satisfies', [], 'value', SpanMapKind.Atom).write(' Override<Config>;\\n');\n\t}\n\n\tconst writer = new Writer()\n\t\t.write('import type Base from ')\n\t\t.map(JSON.stringify(specifier), 0, 0, SpanMapKind.Atom)\n\t\t.write(';\\n\\ntype Config = typeof Base;\\n');\n\tif (statements.text !== '') {\n\t\twriter.write(\n\t\t\t'type Override<T> = T extends readonly unknown[]\\n\\t? T\\n\\t: T extends object\\n\\t\\t? [keyof T] extends [never]\\n\\t\\t\\t? { readonly [key: string]: never }\\n\\t\\t\\t: { readonly [K in keyof T]?: Override<T[K]> }\\n\\t\\t: T;\\n',\n\t\t);\n\t}\n\tif (usesAt) writer.write('type At<T, K> = T extends object ? (K extends keyof T ? T[K] : any) : any;\\n');\n\tif (statements.text !== '') writer.write('\\n').append(statements);\n\treturn writer.write('\\ndeclare const config: Config;\\nexport default config;\\n');\n};\n\n/**\n * Turns a config file into a TypeScript module for a content mapper. A base file declares its widened, readonly type. An\n * environment or local file checks each of its keys against the base file's type, with every key and value mapped back to the\n * config file, and exports the base file's type.\n */\nexport const generateTypes = (path: string, text: string, options: GenerateOptions = {}): GeneratedModule => {\n\tconst file = resolve(path);\n\tconst role = configFileRole(basename(file));\n\tif (!role) {\n\t\tconst message = `${basename(file)} is not a config file. tyfigo handles files ending in ${configSuffixes.join(', ')}`;\n\t\treturn untyped([toDiagnostic(fileProblem(file, 'unsupported-file', message))]);\n\t}\n\n\tconst parsed = role.format.parse(text, file);\n\tconst diagnostics = parsed.problems.map(toDiagnostic);\n\tif (parsed.value === undefined || parsed.problems.some((problem) => problem.code === 'parse-error')) {\n\t\treturn untyped(diagnostics);\n\t}\n\n\tconst generator = new Generator(text, parsed.positions, role.format);\n\tconst placeholders = resolvePlaceholders({\n\t\tvalue: parsed.value,\n\t\tpositions: parsed.positions,\n\t\tsource: generator.source,\n\t\tfile,\n\t\tformat: role.format,\n\t\tvariables: {},\n\t});\n\tfor (const problem of placeholders.problems) {\n\t\tif (problem.code === 'invalid-placeholder') diagnostics.push(toDiagnostic(problem));\n\t}\n\n\tconst base = options.base === undefined ? resolve(dirname(file), role.base) : resolve(options.base);\n\tconst writer =\n\t\tbase === file\n\t\t\t? baseModule(generator, parsed.value)\n\t\t\t: layerModule(generator, parsed.value, importSpecifier(file, base));\n\treturn { text: writer.text, extension: '.ts', mappings: writer.mappings, diagnostics };\n};\n","import { generateTypes } from './generate.ts';\nimport { RpcError, RpcErrorCode } from './rpc.ts';\n\nimport type { RpcHandler } from './rpc.ts';\n\nexport const diagnosticSource = 'tyfigo';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * A content mapper for TypeScript's `contentMappers`. It keeps no state per project: a transform reads only the text it is sent,\n * and an environment file reaches its base file through the `import type` in its generated module, so TypeScript tracks that\n * dependency itself.\n */\nexport const createServer = (): RpcHandler => (method, params) => {\n\tswitch (method) {\n\t\tcase 'initialize':\n\t\t\t// The protocol spells the encoding `utf-8`.\n\t\t\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\t\t\treturn { positionEncoding: 'utf-8', diagnosticSource };\n\t\tcase 'openProject':\n\t\t\treturn {};\n\t\tcase 'transform':\n\t\t\tif (!isRecord(params) || typeof params.fileName !== 'string' || typeof params.content !== 'string') {\n\t\t\t\tthrow new RpcError(RpcErrorCode.InvalidParams, 'transform expects a fileName and content');\n\t\t\t}\n\t\t\treturn generateTypes(params.fileName, params.content);\n\t\tcase 'closeProject':\n\t\t\treturn null;\n\t\tdefault:\n\t\t\tthrow new RpcError(RpcErrorCode.MethodNotFound, `Unknown method ${method}`);\n\t}\n};\n","import process from 'node:process';\n\nimport { serve } from './mapper/rpc.ts';\nimport { createServer } from './mapper/server.ts';\n\nawait serve(createServer(), process.stdin, process.stdout);\n"],"mappings":"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"}
1
+ {"version":3,"file":"mapper.mjs","names":[],"sources":["../src/mapper/rpc.ts","../src/mapper/generate.ts","../src/mapper/server.ts","../src/mapper.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\n\nimport type { Readable, Writable } from 'node:stream';\n\nexport type RequestId = number | string | null;\n\nexport interface RpcMessage {\n\treadonly jsonrpc: '2.0';\n\treadonly id?: RequestId;\n\treadonly method?: string;\n\treadonly params?: unknown;\n}\n\nexport class RpcError extends Error {\n\treadonly code: number;\n\n\tconstructor(code: number, message: string) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\nexport const RpcErrorCode = {\n\tParseError: -32_700,\n\tInvalidRequest: -32_600,\n\tMethodNotFound: -32_601,\n\tInvalidParams: -32_602,\n\tInternalError: -32_603,\n} as const;\n\n/**\n * Handles one request or notification and returns its result.\n */\nexport type RpcHandler = (method: string, params: unknown) => unknown;\n\nconst separator = Buffer.from('\\r\\n\\r\\n');\n\nexport const encodeMessage = (message: unknown): Buffer => {\n\tconst body = Buffer.from(JSON.stringify(message), 'utf8');\n\treturn Buffer.concat([Buffer.from(`Content-Length: ${body.length}\\r\\n\\r\\n`, 'ascii'), body]);\n};\n\n/**\n * Splits a stream of `Content-Length` framed chunks into message bodies.\n */\nexport class MessageReader {\n\t#buffer: Buffer = Buffer.alloc(0);\n\n\tpush(chunk: Buffer): string[] {\n\t\tthis.#buffer = Buffer.concat([this.#buffer, chunk]);\n\t\tconst bodies: string[] = [];\n\t\tfor (;;) {\n\t\t\tconst end = this.#buffer.indexOf(separator);\n\t\t\tif (end === -1) return bodies;\n\t\t\tconst header = this.#buffer.subarray(0, end).toString('ascii');\n\t\t\tconst match = /^content-length:\\s*(\\d+)\\s*$/imu.exec(header);\n\t\t\tif (!match) throw new RpcError(RpcErrorCode.ParseError, `Missing Content-Length in header: ${header}`);\n\t\t\tconst start = end + separator.length;\n\t\t\tconst length = Number(match[1]);\n\t\t\tif (this.#buffer.length < start + length) return bodies;\n\t\t\tbodies.push(this.#buffer.subarray(start, start + length).toString('utf8'));\n\t\t\tthis.#buffer = this.#buffer.subarray(start + length);\n\t\t}\n\t}\n}\n\nconst isMessage = (value: unknown): value is RpcMessage =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * The response to one message body, or `undefined` for a notification.\n */\nexport const dispatch = (body: string, handle: RpcHandler): object | undefined => {\n\tlet message: unknown;\n\ttry {\n\t\tmessage = JSON.parse(body);\n\t} catch (error) {\n\t\treturn { jsonrpc: '2.0', id: null, error: { code: RpcErrorCode.ParseError, message: String(error) } };\n\t}\n\n\tif (!isMessage(message) || typeof message.method !== 'string') {\n\t\tconst id = isMessage(message) ? (message.id ?? null) : null;\n\t\treturn { jsonrpc: '2.0', id, error: { code: RpcErrorCode.InvalidRequest, message: 'Invalid request' } };\n\t}\n\n\tconst isNotification = !('id' in message);\n\ttry {\n\t\tconst result = handle(message.method, message.params);\n\t\treturn isNotification ? undefined : { jsonrpc: '2.0', id: message.id ?? null, result: result ?? null };\n\t} catch (error) {\n\t\tif (isNotification) return undefined;\n\t\tconst code = error instanceof RpcError ? error.code : RpcErrorCode.InternalError;\n\t\tconst text = error instanceof Error ? error.message : String(error);\n\t\treturn { jsonrpc: '2.0', id: message.id ?? null, error: { code, message: text } };\n\t}\n};\n\n/**\n * Answers JSON-RPC 2.0 messages from `input` on `output` until `input` ends.\n */\nexport const serve = (handle: RpcHandler, input: Readable, output: Writable): Promise<void> =>\n\tnew Promise((resolve, reject) => {\n\t\tconst reader = new MessageReader();\n\t\tinput.on('data', (chunk: Buffer) => {\n\t\t\tlet bodies: string[];\n\t\t\ttry {\n\t\t\t\tbodies = reader.push(chunk);\n\t\t\t} catch (error) {\n\t\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const body of bodies) {\n\t\t\t\tconst response = dispatch(body, handle);\n\t\t\t\tif (response) output.write(encodeMessage(response));\n\t\t\t}\n\t\t});\n\t\tinput.once('end', () => resolve());\n\t\tinput.once('error', reject);\n\t});\n","import { Buffer } from 'node:buffer';\nimport { basename, dirname, extname, relative, resolve } from 'node:path';\n\nimport { formatExtensions, formatOfExtension, parseConfigPath } from '../core/formats/index.ts';\nimport { isPlainObject, resolvePlaceholders } from '../core/placeholders.ts';\nimport { pathKey, SourceIndex } from '../core/positions.ts';\nimport { fileProblem } from '../core/problems.ts';\n\nimport type { Format } from '../core/formats/index.ts';\nimport type { LayerKind } from '../core/layers.ts';\nimport type { Path, PositionMap } from '../core/positions.ts';\nimport type { Problem, ProblemCode } from '../core/problems.ts';\n\nexport const SpanMapKind = { Verbatim: 0, Atom: 1, Alias: 2 } as const;\nexport type SpanMapKind = (typeof SpanMapKind)[keyof typeof SpanMapKind];\n\n/**\n * `[virtualStart, virtualLength, originalStart, originalLength, kind]` in UTF-8 bytes.\n */\nexport type SpanMapping = readonly [\n\tvirtualStart: number,\n\tvirtualLength: number,\n\toriginalStart: number,\n\toriginalLength: number,\n\tkind: SpanMapKind,\n];\n\n/**\n * A problem in the original file. `start` and `length` are UTF-8 byte offsets.\n */\nexport interface MapperDiagnostic {\n\treadonly messageText: string;\n\treadonly start: number;\n\treadonly length: number;\n\treadonly code: number;\n}\n\nexport interface GeneratedModule {\n\treadonly text: string;\n\treadonly extension: '.ts';\n\treadonly mappings: readonly SpanMapping[];\n\treadonly diagnostics: readonly MapperDiagnostic[];\n}\n\nexport interface GenerateOptions {\n\t/**\n\t * The base config file this file layers on. Defaults to the name implied by `path` (`app.config.yaml` for\n\t * `app.production.config.yaml`). When it is `path` itself, `path` is generated as the base file.\n\t */\n\treadonly base?: string | undefined;\n}\n\nexport const diagnosticCodes: Readonly<Record<ProblemCode, number>> = {\n\t'parse-error': 1_001,\n\t'duplicate-key': 1_002,\n\t'file-not-found': 1_003,\n\t'read-error': 1_004,\n\t'unsupported-file': 1_005,\n\t'missing-variable': 1_006,\n\t'invalid-placeholder': 1_007,\n\t'unknown-key': 1_008,\n\t'type-mismatch': 1_009,\n\t'browser-placeholder': 1_010,\n\t'placeholder-type': 1_011,\n};\n\nexport interface ConfigFileRole {\n\treadonly kind: LayerKind;\n\t/**\n\t * The base file's name, `app.config.yaml` for `app.production.local.config.yaml` and `app.yaml` for\n\t * `.config/app.production.yaml`.\n\t */\n\treadonly base: string;\n\treadonly environment: string | undefined;\n\treadonly format: Format;\n}\n\n/**\n * Reads a config file's layer from its path: the first dot-separated part of the stem names the base file, a trailing `local`\n * marks a local file and anything in between is the environment.\n */\nexport const configFileRole = (path: string): ConfigFileRole | undefined => {\n\tconst name = parseConfigPath(path);\n\tif (!name) return undefined;\n\tconst [stem = '', ...rest] = name.stem.split('.');\n\tconst base = `${stem}${name.suffix}`;\n\tconst isLocal = rest.at(-1) === 'local';\n\tconst environment = (isLocal ? rest.slice(0, -1) : rest).join('.') || undefined;\n\tconst kind: LayerKind = isLocal\n\t\t? environment\n\t\t\t? 'environment-local'\n\t\t\t: 'local'\n\t\t: environment\n\t\t\t? 'environment'\n\t\t\t: 'base';\n\treturn { kind, base, environment, format: name.format };\n};\n\nconst wholePlaceholder = /^\\$\\{[A-Za-z_]\\w*(?:(:-|:\\?)([^}]*))?\\}$/u;\n\nconst identifier = /^[A-Za-z_$][\\w$]*$/u;\n\nconst isStringLiteral = (text: string, value: string) =>\n\ttext === JSON.stringify(value) || (text === `'${value}'` && !/['\\\\\\n\\r\\u2028\\u2029]/u.test(value));\n\nconst numberLiteral = (value: number) =>\n\tNumber.isNaN(value) ? 'NaN' : Number.isFinite(value) ? String(value) : value > 0 ? 'Infinity' : '-Infinity';\n\nclass Writer {\n\ttext = '';\n\tbytes = 0;\n\treadonly mappings: SpanMapping[] = [];\n\n\twrite(text: string): this {\n\t\tthis.text += text;\n\t\tthis.bytes += Buffer.byteLength(text);\n\t\treturn this;\n\t}\n\n\tmap(text: string, start: number, length: number, kind: SpanMapKind): this {\n\t\tthis.mappings.push([this.bytes, Buffer.byteLength(text), start, length, kind]);\n\t\treturn this.write(text);\n\t}\n\n\tappend(other: Writer): this {\n\t\tfor (const [start, ...rest] of other.mappings) this.mappings.push([start + this.bytes, ...rest]);\n\t\treturn this.write(other.text);\n\t}\n}\n\nclass Generator {\n\treadonly source: SourceIndex;\n\treadonly positions: PositionMap;\n\treadonly format: Format;\n\treadonly placeholders: boolean;\n\n\tconstructor(text: string, positions: PositionMap, format: Format, placeholders = true) {\n\t\tthis.source = new SourceIndex(text);\n\t\tthis.positions = positions;\n\t\tthis.format = format;\n\t\tthis.placeholders = placeholders;\n\t}\n\n\t#slice(start: number, length: number) {\n\t\treturn this.source.text.slice(this.source.charIndex(start), this.source.charIndex(start + length));\n\t}\n\n\t#original(path: Path, part: 'key' | 'value') {\n\t\tconst span = this.positions.get(pathKey(path));\n\t\tif (!span) return undefined;\n\t\treturn part === 'key'\n\t\t\t? this.#slice(span.keyStart, span.keyLength)\n\t\t\t: this.#slice(span.valueStart, span.valueLength);\n\t}\n\n\t/**\n\t * Writes a property name, reusing the original spelling when it is valid TypeScript for the same key.\n\t */\n\tkey(writer: Writer, key: string, path: Path) {\n\t\tconst original = this.#original(path, 'key');\n\t\tconst text =\n\t\t\toriginal !== undefined && isStringLiteral(original, key)\n\t\t\t\t? original\n\t\t\t\t: identifier.test(key)\n\t\t\t\t\t? key\n\t\t\t\t\t: JSON.stringify(key);\n\t\treturn this.mapped(writer, text, path, 'key');\n\t}\n\n\tstring(value: string, path: Path) {\n\t\tconst original = this.#original(path, 'value');\n\t\treturn original !== undefined && isStringLiteral(original, value) ? original : JSON.stringify(value);\n\t}\n\n\t/**\n\t * Writes `text` mapped to the key or value of `path`: Verbatim when it is the original text, `fallback` otherwise.\n\t */\n\tmapped(writer: Writer, text: string, path: Path, part: 'key' | 'value', fallback: SpanMapKind = SpanMapKind.Alias) {\n\t\tconst span = this.positions.get(pathKey(path));\n\t\tif (!span) return writer.write(text);\n\t\tconst [start, length] = part === 'key' ? [span.keyStart, span.keyLength] : [span.valueStart, span.valueLength];\n\t\treturn writer.map(text, start, length, this.#slice(start, length) === text ? SpanMapKind.Verbatim : fallback);\n\t}\n\n\tplaceholderType(text: string) {\n\t\tconst match = this.placeholders ? wholePlaceholder.exec(text) : null;\n\t\tif (match?.[1] !== ':-') return 'string';\n\t\tconst value = this.format.parseScalar(match[2] ?? '');\n\t\treturn value === null ? 'null' : typeof value;\n\t}\n\n\ttype(value: unknown, path: Path, indent: string): Writer {\n\t\tconst writer = new Writer();\n\t\tif (Array.isArray(value)) return this.#arrayType(value, path, indent);\n\t\tif (isPlainObject(value)) {\n\t\t\tconst entries = Object.entries(value);\n\t\t\tif (entries.length === 0) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\tthis.mapped(writer, '{', path, 'value', SpanMapKind.Atom).write('\\n');\n\t\t\tfor (const [key, item] of entries) {\n\t\t\t\tconst childPath = [...path, key];\n\t\t\t\twriter.write(`${indent}\\treadonly `);\n\t\t\t\tthis.key(writer, key, childPath);\n\t\t\t\twriter\n\t\t\t\t\t.write(': ')\n\t\t\t\t\t.append(this.type(item, childPath, `${indent}\\t`))\n\t\t\t\t\t.write(';\\n');\n\t\t\t}\n\t\t\treturn writer.write(`${indent}}`);\n\t\t}\n\n\t\tconst text =\n\t\t\tvalue === null\n\t\t\t\t? 'null'\n\t\t\t\t: typeof value === 'string'\n\t\t\t\t\t? this.placeholderType(value)\n\t\t\t\t\t: typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint'\n\t\t\t\t\t\t? typeof value\n\t\t\t\t\t\t: 'unknown';\n\t\treturn this.mapped(writer, text, path, 'value');\n\t}\n\n\t#arrayType(items: readonly unknown[], path: Path, indent: string) {\n\t\tconst members = new Map<string, Writer>();\n\t\tfor (const [index, item] of items.entries()) {\n\t\t\tconst member = this.type(item, [...path, index], indent);\n\t\t\tif (!members.has(member.text)) members.set(member.text, member);\n\t\t}\n\n\t\tconst writer = this.mapped(new Writer(), 'readonly', path, 'value', SpanMapKind.Atom).write(' ');\n\t\tif (members.size === 0) return writer.write('unknown[]');\n\t\tconst [first] = members.values();\n\t\tconst wrap = members.size > 1 || first?.text.startsWith('readonly');\n\t\tif (wrap) writer.write('(');\n\t\tfor (const [index, member] of [...members.values()].entries()) {\n\t\t\tif (index > 0) writer.write(' | ');\n\t\t\twriter.append(member);\n\t\t}\n\t\treturn writer.write(wrap ? ')[]' : '[]');\n\t}\n\n\t/**\n\t * An expression for `value`. Objects that are not inside an array become `{}` when `shallow` is set, because their keys are\n\t * checked by statements of their own.\n\t */\n\tvalue(value: unknown, path: Path, shallow: boolean): Writer {\n\t\tconst writer = new Writer();\n\t\tif (Array.isArray(value)) {\n\t\t\twriter.write('[');\n\t\t\tfor (const [index, item] of value.entries()) {\n\t\t\t\tif (index > 0) writer.write(', ');\n\t\t\t\twriter.append(this.value(item, [...path, index], false));\n\t\t\t}\n\t\t\treturn writer.write(']');\n\t\t}\n\n\t\tif (isPlainObject(value)) {\n\t\t\tif (shallow) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\tconst entries = Object.entries(value);\n\t\t\tif (entries.length === 0) return this.mapped(writer, '{}', path, 'value', SpanMapKind.Atom);\n\t\t\twriter.write('{ ');\n\t\t\tfor (const [index, [key, item]] of entries.entries()) {\n\t\t\t\tconst childPath = [...path, key];\n\t\t\t\tif (index > 0) writer.write(', ');\n\t\t\t\tthis.key(writer, key, childPath);\n\t\t\t\twriter.write(': ').append(this.value(item, childPath, false));\n\t\t\t}\n\t\t\treturn writer.write(' }');\n\t\t}\n\n\t\tif (typeof value === 'string' && wholePlaceholder.test(value)) {\n\t\t\treturn this.mapped(writer, '(undefined as never)', path, 'value');\n\t\t}\n\n\t\tconst text =\n\t\t\tvalue === null || typeof value === 'boolean'\n\t\t\t\t? String(value)\n\t\t\t\t: typeof value === 'string'\n\t\t\t\t\t? this.string(value, path)\n\t\t\t\t\t: typeof value === 'number'\n\t\t\t\t\t\t? numberLiteral(value)\n\t\t\t\t\t\t: typeof value === 'bigint'\n\t\t\t\t\t\t\t? `${value}n`\n\t\t\t\t\t\t\t: '(undefined as never)';\n\t\treturn this.mapped(writer, text, path, 'value');\n\t}\n}\n\nconst toDiagnostic = (problem: Problem): MapperDiagnostic => ({\n\tmessageText: problem.message,\n\tstart: problem.start,\n\tlength: problem.length,\n\tcode: diagnosticCodes[problem.code],\n});\n\nconst untyped = (diagnostics: readonly MapperDiagnostic[]): GeneratedModule => ({\n\ttext: 'declare const config: any;\\nexport default config;\\n',\n\textension: '.ts',\n\tmappings: [],\n\tdiagnostics,\n});\n\nconst baseModule = (generator: Generator, value: unknown) =>\n\tnew Writer()\n\t\t.write('declare const config: ')\n\t\t.append(generator.type(value, [], ''))\n\t\t.write(';\\nexport default config;\\n');\n\nconst importSpecifier = (from: string, to: string) => {\n\tconst specifier = relative(dirname(from), to).replaceAll('\\\\', '/');\n\treturn specifier.startsWith('.') ? specifier : `./${specifier}`;\n};\n\nconst layerModule = (generator: Generator, value: unknown, specifier: string) => {\n\tconst statements = new Writer();\n\n\tconst visit = (object: Record<string, unknown>, path: Path, target: string): boolean => {\n\t\tlet nested = false;\n\t\tfor (const [key, item] of Object.entries(object)) {\n\t\t\tconst childPath = [...path, key];\n\t\t\tstatements.write('({ ');\n\t\t\tgenerator.key(statements, key, childPath);\n\t\t\tstatements.write(': ').append(generator.value(item, childPath, true));\n\t\t\tstatements.write(` }) satisfies Override<${target}>;\\n`);\n\t\t\tif (isPlainObject(item)) {\n\t\t\t\tnested = true;\n\t\t\t\tvisit(item, childPath, `At<${target}, ${JSON.stringify(key)}>`);\n\t\t\t}\n\t\t}\n\t\treturn nested;\n\t};\n\n\tlet usesAt = false;\n\tif (isPlainObject(value)) usesAt = visit(value, [], 'Config');\n\telse {\n\t\tstatements.write('(').append(generator.value(value, [], false));\n\t\tstatements.write(') ');\n\t\tgenerator.mapped(statements, 'satisfies', [], 'value', SpanMapKind.Atom).write(' Override<Config>;\\n');\n\t}\n\n\tconst writer = new Writer()\n\t\t.write('import type Base from ')\n\t\t.map(JSON.stringify(specifier), 0, 0, SpanMapKind.Atom)\n\t\t.write(';\\n\\ntype Config = typeof Base;\\n');\n\tif (statements.text !== '') {\n\t\twriter.write(\n\t\t\t'type Override<T> = T extends readonly unknown[]\\n\\t? T\\n\\t: T extends object\\n\\t\\t? [keyof T] extends [never]\\n\\t\\t\\t? { readonly [key: string]: never }\\n\\t\\t\\t: { readonly [K in keyof T]?: Override<T[K]> }\\n\\t\\t: T;\\n',\n\t\t);\n\t}\n\tif (usesAt) writer.write('type At<T, K> = T extends object ? (K extends keyof T ? T[K] : any) : any;\\n');\n\tif (statements.text !== '') writer.write('\\n').append(statements);\n\treturn writer.write('\\ndeclare const config: Config;\\nexport default config;\\n');\n};\n\nconst dataModule = (file: string, text: string, format: Format): GeneratedModule => {\n\tconst parsed = format.parse(text, file);\n\tconst diagnostics = parsed.problems.map(toDiagnostic);\n\tif (parsed.value === undefined || parsed.problems.some((problem) => problem.code === 'parse-error')) {\n\t\treturn untyped(diagnostics);\n\t}\n\tconst writer = baseModule(new Generator(text, parsed.positions, format, false), parsed.value);\n\treturn { text: writer.text, extension: '.ts', mappings: writer.mappings, diagnostics };\n};\n\n/**\n * Turns a config file into a TypeScript module for a content mapper. A base file declares its widened, readonly type. An\n * environment or local file checks each of its keys against the base file's type, with every key and value mapped back to the\n * config file, and exports the base file's type. Any other file of a format extension, such as `data.yaml` when a project\n * claims `.yaml`, declares its widened, readonly type as plain data, with no layers or placeholders.\n */\nexport const generateTypes = (path: string, text: string, options: GenerateOptions = {}): GeneratedModule => {\n\tconst file = resolve(path);\n\tconst role = configFileRole(file);\n\tif (!role) {\n\t\tconst format = formatOfExtension(extname(file));\n\t\tif (format) return dataModule(file, text, format);\n\t\tconst message = `${basename(file)} is not a file tyfigo reads. tyfigo handles files ending in ${Object.keys(formatExtensions).join(', ')}`;\n\t\treturn untyped([toDiagnostic(fileProblem(file, 'unsupported-file', message))]);\n\t}\n\n\tconst parsed = role.format.parse(text, file);\n\tconst diagnostics = parsed.problems.map(toDiagnostic);\n\tif (parsed.value === undefined || parsed.problems.some((problem) => problem.code === 'parse-error')) {\n\t\treturn untyped(diagnostics);\n\t}\n\n\tconst generator = new Generator(text, parsed.positions, role.format);\n\tconst placeholders = resolvePlaceholders({\n\t\tvalue: parsed.value,\n\t\tpositions: parsed.positions,\n\t\tsource: generator.source,\n\t\tfile,\n\t\tformat: role.format,\n\t\tvariables: {},\n\t});\n\tfor (const problem of placeholders.problems) {\n\t\tif (problem.code === 'invalid-placeholder') diagnostics.push(toDiagnostic(problem));\n\t}\n\n\tconst base = options.base === undefined ? resolve(dirname(file), role.base) : resolve(options.base);\n\tconst writer =\n\t\tbase === file\n\t\t\t? baseModule(generator, parsed.value)\n\t\t\t: layerModule(generator, parsed.value, importSpecifier(file, base));\n\treturn { text: writer.text, extension: '.ts', mappings: writer.mappings, diagnostics };\n};\n","import { generateTypes } from './generate.ts';\nimport { RpcError, RpcErrorCode } from './rpc.ts';\n\nimport type { RpcHandler } from './rpc.ts';\n\nexport const diagnosticSource = 'tyfigo';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * A content mapper for TypeScript's `contentMappers`. It keeps no state per project: a transform reads only the text it is sent,\n * and an environment file reaches its base file through the `import type` in its generated module, so TypeScript tracks that\n * dependency itself.\n */\nexport const createServer = (): RpcHandler => (method, params) => {\n\tswitch (method) {\n\t\tcase 'initialize':\n\t\t\t// The protocol spells the encoding `utf-8`.\n\t\t\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\t\t\treturn { positionEncoding: 'utf-8', diagnosticSource };\n\t\tcase 'openProject':\n\t\t\treturn {};\n\t\tcase 'transform':\n\t\t\tif (!isRecord(params) || typeof params.fileName !== 'string' || typeof params.content !== 'string') {\n\t\t\t\tthrow new RpcError(RpcErrorCode.InvalidParams, 'transform expects a fileName and content');\n\t\t\t}\n\t\t\treturn generateTypes(params.fileName, params.content);\n\t\tcase 'closeProject':\n\t\t\treturn null;\n\t\tdefault:\n\t\t\tthrow new RpcError(RpcErrorCode.MethodNotFound, `Unknown method ${method}`);\n\t}\n};\n","import process from 'node:process';\n\nimport { serve } from './mapper/rpc.ts';\nimport { createServer } from './mapper/server.ts';\n\nawait serve(createServer(), process.stdin, process.stdout);\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("esbuild").Plugin;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=esbuild.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/esbuild.ts
3
3
  var esbuild_default = tyfigo.esbuild;
4
4
  export { esbuild_default as default };
@@ -1,4 +1,4 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
2
  import { SyncTransformer } from "@jest/transform";
3
3
  export type TyfigoJestOptions = Omit<TyfigoPluginOptions, 'target'>;
4
4
  /**
@@ -1,7 +1,7 @@
1
- import { n as formatProblems } from "../problems-BNAqmOzL.mjs";
2
- import { n as resolveConfigSync } from "../sync-B-HAK-_E.mjs";
3
- import { r as valueLiteral } from "../load-DxIjRpX6.mjs";
4
- import { i as loadConfigImport } from "../shared-BnK77Zcp.mjs";
1
+ import { n as formatProblems } from "../problems-DS_eJB6e.mjs";
2
+ import { n as resolveConfigSync } from "../sync-mWkXcCOW.mjs";
3
+ import { r as valueLiteral } from "../load-yFCdP4to.mjs";
4
+ import { r as loadConfigImport } from "../shared-DOMPQnVO.mjs";
5
5
  import { createHash } from "node:crypto";
6
6
  // src/plugins/jest.ts
7
7
  const generate = (file, options) => {
@@ -1,4 +1,4 @@
1
- import { n as WebpackLikePlatform, t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
1
+ import { n as WebpackLikePlatform, t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
2
  export interface TyfigoLoaderContext {
3
3
  readonly resourcePath: string;
4
4
  readonly getOptions: () => TyfigoPluginOptions;
@@ -1,4 +1,5 @@
1
- import { i as loadConfigImport, n as findNodeOnlyImports, r as isServerPlatform, t as configFilePattern } from "../shared-BnK77Zcp.mjs";
1
+ import { n as configPathPattern } from "../formats-Bf8-iQw-.mjs";
2
+ import { n as isServerPlatform, r as loadConfigImport, t as findNodeOnlyImports } from "../shared-DOMPQnVO.mjs";
2
3
  // src/plugins/loader.ts
3
4
  /**
4
5
  * A webpack loader for config files, for webpack-compatible loader runners such as Turbopack's. Without a `target` option it
@@ -6,7 +7,7 @@ import { i as loadConfigImport, n as findNodeOnlyImports, r as isServerPlatform,
6
7
  * is returned unchanged, and fails when it imports a tyfigo export that needs Node.js, which is how client code is checked.
7
8
  */
8
9
  function tyfigoLoader(source) {
9
- if (!configFilePattern.test(this.resourcePath)) {
10
+ if (!configPathPattern.test(this.resourcePath)) {
10
11
  const messages = findNodeOnlyImports(source, this.resourcePath);
11
12
  if (messages.length > 0) throw new Error(messages.join("\n"));
12
13
  return source;
@@ -1 +1 @@
1
- {"version":3,"file":"loader.mjs","names":[],"sources":["../../src/plugins/loader.ts"],"sourcesContent":["import { configFilePattern, findNodeOnlyImports, isServerPlatform, loadConfigImport } from './shared.ts';\n\nimport type { TyfigoPluginOptions, WebpackLikePlatform } from './shared.ts';\n\nexport interface TyfigoLoaderContext {\n\treadonly resourcePath: string;\n\treadonly getOptions: () => TyfigoPluginOptions;\n\treadonly addDependency: (file: string) => void;\n\treadonly _compiler?: { readonly platform: WebpackLikePlatform } | undefined;\n}\n\n/**\n * A webpack loader for config files, for webpack-compatible loader runners such as Turbopack's. Without a `target` option it\n * detects the target from the compiler's platform when the runner exposes one, and falls back to `browser`. Any other module\n * is returned unchanged, and fails when it imports a tyfigo export that needs Node.js, which is how client code is checked.\n */\nexport default function tyfigoLoader(this: TyfigoLoaderContext, source: string): string {\n\tif (!configFilePattern.test(this.resourcePath)) {\n\t\tconst messages = findNodeOnlyImports(source, this.resourcePath);\n\t\tif (messages.length > 0) throw new Error(messages.join('\\n'));\n\t\treturn source;\n\t}\n\n\tconst options = this.getOptions();\n\tconst target =\n\t\toptions.target ?? (this._compiler && isServerPlatform(this._compiler.platform) ? 'server' : 'browser');\n\tconst result = loadConfigImport(this.resourcePath, {\n\t\ttarget,\n\t\tbundle: true,\n\t\tenvironment: options.environment,\n\t\truntime: options.runtime,\n\t});\n\tfor (const file of result.watchFiles) this.addDependency(file);\n\treturn result.code;\n}\n"],"mappings":";;;;;;;AAgBA,SAAwB,aAAwC,QAAwB;CACvF,IAAI,CAAC,kBAAkB,KAAK,KAAK,YAAY,GAAG;EAC/C,MAAM,WAAW,oBAAoB,QAAQ,KAAK,YAAY;EAC9D,IAAI,SAAS,SAAS,GAAG,MAAM,IAAI,MAAM,SAAS,KAAK,IAAI,CAAC;EAC5D,OAAO;CACR;CAEA,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SACL,QAAQ,WAAW,KAAK,aAAa,iBAAiB,KAAK,UAAU,QAAQ,IAAI,WAAW;CAC7F,MAAM,SAAS,iBAAiB,KAAK,cAAc;EAClD;EACA,QAAQ;EACR,aAAa,QAAQ;EACrB,SAAS,QAAQ;CAClB,CAAC;CACD,KAAK,MAAM,QAAQ,OAAO,YAAY,KAAK,cAAc,IAAI;CAC7D,OAAO,OAAO;AACf"}
1
+ {"version":3,"file":"loader.mjs","names":[],"sources":["../../src/plugins/loader.ts"],"sourcesContent":["import { findNodeOnlyImports, isServerPlatform, loadConfigImport } from './shared.ts';\n\nimport { configPathPattern } from '../core/index.ts';\n\nimport type { TyfigoPluginOptions, WebpackLikePlatform } from './shared.ts';\n\nexport interface TyfigoLoaderContext {\n\treadonly resourcePath: string;\n\treadonly getOptions: () => TyfigoPluginOptions;\n\treadonly addDependency: (file: string) => void;\n\treadonly _compiler?: { readonly platform: WebpackLikePlatform } | undefined;\n}\n\n/**\n * A webpack loader for config files, for webpack-compatible loader runners such as Turbopack's. Without a `target` option it\n * detects the target from the compiler's platform when the runner exposes one, and falls back to `browser`. Any other module\n * is returned unchanged, and fails when it imports a tyfigo export that needs Node.js, which is how client code is checked.\n */\nexport default function tyfigoLoader(this: TyfigoLoaderContext, source: string): string {\n\tif (!configPathPattern.test(this.resourcePath)) {\n\t\tconst messages = findNodeOnlyImports(source, this.resourcePath);\n\t\tif (messages.length > 0) throw new Error(messages.join('\\n'));\n\t\treturn source;\n\t}\n\n\tconst options = this.getOptions();\n\tconst target =\n\t\toptions.target ?? (this._compiler && isServerPlatform(this._compiler.platform) ? 'server' : 'browser');\n\tconst result = loadConfigImport(this.resourcePath, {\n\t\ttarget,\n\t\tbundle: true,\n\t\tenvironment: options.environment,\n\t\truntime: options.runtime,\n\t});\n\tfor (const file of result.watchFiles) this.addDependency(file);\n\treturn result.code;\n}\n"],"mappings":";;;;;;;;AAkBA,SAAwB,aAAwC,QAAwB;CACvF,IAAI,CAAC,kBAAkB,KAAK,KAAK,YAAY,GAAG;EAC/C,MAAM,WAAW,oBAAoB,QAAQ,KAAK,YAAY;EAC9D,IAAI,SAAS,SAAS,GAAG,MAAM,IAAI,MAAM,SAAS,KAAK,IAAI,CAAC;EAC5D,OAAO;CACR;CAEA,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SACL,QAAQ,WAAW,KAAK,aAAa,iBAAiB,KAAK,UAAU,QAAQ,IAAI,WAAW;CAC7F,MAAM,SAAS,iBAAiB,KAAK,cAAc;EAClD;EACA,QAAQ;EACR,aAAa,QAAQ;EACrB,SAAS,QAAQ;CAClB,CAAC;CACD,KAAK,MAAM,QAAQ,OAAO,YAAY,KAAK,cAAc,IAAI;CAC7D,OAAO,OAAO;AACf"}
@@ -1,4 +1,4 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
2
  import { NextConfig } from "next";
3
3
  export interface WithTyfigoOptions extends Omit<TyfigoPluginOptions, 'target'> {
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { t as configSuffixes } from "../formats-D_dKXoPf.mjs";
2
- import { t as configFilePattern } from "../shared-BnK77Zcp.mjs";
1
+ import { i as configDirectory } from "../problems-DS_eJB6e.mjs";
2
+ import { i as formatExtensions, n as configPathPattern, r as configSuffixes } from "../formats-Bf8-iQw-.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { dirname, extname, join, resolve } from "node:path";
5
5
  import process from "node:process";
@@ -16,10 +16,15 @@ const loaderOptions = (options, target) => ({
16
16
  });
17
17
  const browser = { any: ["browser", "edge-light"] };
18
18
  /**
19
+ * The `turbopack.rules` globs for config files: `*.config.yaml` and the other suffixes match file names, and the `.config`
20
+ * directory globs, which contain a `/`, match project-relative paths.
21
+ */
22
+ const turbopackGlobs = [...configSuffixes.map((suffix) => `*${suffix}`), ...Object.keys(formatExtensions).map((extension) => `**/${configDirectory}/*${extension}`)];
23
+ /**
19
24
  * `turbopack.rules` that load config files with the tyfigo loader: client and Edge code gets the browser module, Node.js
20
25
  * server code the bundled server module.
21
26
  */
22
- const turbopackRules = (options = {}) => Object.fromEntries(configSuffixes.map((suffix) => [`*${suffix}`, [{
27
+ const turbopackRules = (options = {}) => Object.fromEntries(turbopackGlobs.map((glob) => [glob, [{
23
28
  condition: browser,
24
29
  loaders: [{
25
30
  loader: loaderPath,
@@ -68,7 +73,7 @@ const typeCheck = async (projectDir, tsconfigPath = "tsconfig.json") => {
68
73
  const withTyfigo = (nextConfig = {}, options = {}) => {
69
74
  const { typeCheck: check = !nextConfig.typescript?.ignoreBuildErrors, ...loader } = options;
70
75
  const rule = (target) => ({
71
- test: configFilePattern,
76
+ test: configPathPattern,
72
77
  type: "javascript/auto",
73
78
  use: [{
74
79
  loader: loaderPath,
@@ -1 +1 @@
1
- {"version":3,"file":"next.mjs","names":[],"sources":["../../src/plugins/turbopack.ts","../../src/plugins/next.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { configSuffixes } from '../core/index.ts';\n\nimport type { LoadTarget } from '../runtime/load.ts';\nimport type { TyfigoPluginOptions } from './shared.ts';\nimport type { TurbopackRuleCondition, TurbopackRuleConfigCollection } from 'next/dist/server/config-shared.js';\n\n// The loader sits next to this module: `loader.mjs` in the package, `loader.ts` when this runs from source.\nexport const loaderPath = fileURLToPath(new URL(`loader${extname(import.meta.url)}`, import.meta.url));\n\nexport const loaderOptions = (options: Omit<TyfigoPluginOptions, 'target'>, target: LoadTarget) => ({\n\ttarget,\n\t...(options.environment === undefined ? {} : { environment: options.environment }),\n\t...(options.runtime === undefined ? {} : { runtime: options.runtime }),\n});\n\nconst browser: TurbopackRuleCondition = { any: ['browser', 'edge-light'] };\n\n/**\n * `turbopack.rules` that load config files with the tyfigo loader: client and Edge code gets the browser module, Node.js\n * server code the bundled server module.\n */\nexport const turbopackRules = (\n\toptions: Omit<TyfigoPluginOptions, 'target'> = {},\n): Record<string, TurbopackRuleConfigCollection> =>\n\tObject.fromEntries(\n\t\tconfigSuffixes.map((suffix) => [\n\t\t\t`*${suffix}`,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcondition: browser,\n\t\t\t\t\tloaders: [{ loader: loaderPath, options: loaderOptions(options, 'browser') }],\n\t\t\t\t\tas: '*.js',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcondition: { not: browser },\n\t\t\t\t\tloaders: [{ loader: loaderPath, options: loaderOptions(options, 'server') }],\n\t\t\t\t\tas: '*.js',\n\t\t\t\t},\n\t\t\t],\n\t\t]),\n\t);\n","import { spawn } from 'node:child_process';\nimport { once } from 'node:events';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport { configFilePattern } from './shared.ts';\nimport { loaderOptions, loaderPath, turbopackRules } from './turbopack.ts';\n\nimport type { TyfigoPluginOptions } from './shared.ts';\nimport type { NextConfig } from 'next';\n\nexport interface WithTyfigoOptions extends Omit<TyfigoPluginOptions, 'target'> {\n\t/**\n\t * `next build` type-checks without `--runExternalCode`, so TypeScript cannot type config imports. When this is on, Next's\n\t * own check is turned off and `tsc --noEmit --runExternalCode` runs after the production compile instead. Defaults to on\n\t * unless `typescript.ignoreBuildErrors` is set.\n\t */\n\treadonly typeCheck?: boolean | undefined;\n}\n\nconst tscPath = (projectDir: string) => {\n\tconst require = createRequire(join(projectDir, 'package.json'));\n\tconst manifest = require.resolve('typescript/package.json');\n\tconst { bin } = require(manifest) as { readonly bin: Readonly<Record<string, string>> };\n\treturn resolve(dirname(manifest), bin.tsc ?? 'bin/tsc');\n};\n\n/**\n * Runs `tsc --noEmit --runExternalCode` for the project's tsconfig, and rejects when it reports errors. Resolves without\n * checking when the tsconfig does not exist.\n */\nexport const typeCheck = async (projectDir: string, tsconfigPath = 'tsconfig.json'): Promise<void> => {\n\tconst project = resolve(projectDir, tsconfigPath);\n\tif (!existsSync(project)) return;\n\tconst tsc = spawn(process.execPath, [tscPath(projectDir), '--noEmit', '--runExternalCode', '--project', project], {\n\t\tcwd: projectDir,\n\t\tstdio: 'inherit',\n\t});\n\tconst [code] = (await once(tsc, 'exit')) as [number | null];\n\tif (code !== 0) throw new Error(`Type check failed: tsc --noEmit --runExternalCode --project ${project}`);\n};\n\n/**\n * Adds tyfigo to a Next.js config: a webpack rule and Turbopack rules for config imports, with the browser rule for client and\n * Edge code, and a type check that can read config imports.\n */\nexport const withTyfigo = (nextConfig: NextConfig = {}, options: WithTyfigoOptions = {}): NextConfig => {\n\tconst { typeCheck: check = !nextConfig.typescript?.ignoreBuildErrors, ...loader } = options;\n\tconst rule = (target: 'server' | 'browser') => ({\n\t\ttest: configFilePattern,\n\t\ttype: 'javascript/auto',\n\t\tuse: [{ loader: loaderPath, options: loaderOptions(loader, target) }],\n\t});\n\tconst config: NextConfig = {\n\t\t...nextConfig,\n\t\texperimental: { useTypeScriptCli: true, ...nextConfig.experimental },\n\t\tturbopack: {\n\t\t\t...nextConfig.turbopack,\n\t\t\trules: { ...turbopackRules(loader), ...nextConfig.turbopack?.rules },\n\t\t},\n\t\twebpack: (webpackConfig: { module: { rules: unknown[] } }, context) => {\n\t\t\tif (!context.isServer || context.nextRuntime === 'edge') {\n\t\t\t\twebpackConfig.module.rules.push(rule('browser'), {\n\t\t\t\t\ttest: /\\.[cm]?[jt]sx?$/u,\n\t\t\t\t\texclude: /[\\\\/]node_modules[\\\\/]/u,\n\t\t\t\t\tenforce: 'pre',\n\t\t\t\t\tuse: [{ loader: loaderPath }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\twebpackConfig.module.rules.push(\n\t\t\t\t\t{ ...rule('browser'), issuerLayer: 'ssr' },\n\t\t\t\t\t{ ...rule('server'), issuerLayer: { not: 'ssr' } },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn nextConfig.webpack ? nextConfig.webpack(webpackConfig, context) : webpackConfig;\n\t\t},\n\t};\n\tif (!check) return config;\n\n\treturn {\n\t\t...config,\n\t\ttypescript: { ...nextConfig.typescript, ignoreBuildErrors: true },\n\t\tcompiler: {\n\t\t\t...nextConfig.compiler,\n\t\t\trunAfterProductionCompile: async (metadata) => {\n\t\t\t\tawait nextConfig.compiler?.runAfterProductionCompile?.(metadata);\n\t\t\t\tawait typeCheck(metadata.projectDir, nextConfig.typescript?.tsconfigPath);\n\t\t\t},\n\t\t},\n\t};\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"next.mjs","names":[],"sources":["../../src/plugins/turbopack.ts","../../src/plugins/next.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { configDirectory } from '../core/files.ts';\nimport { configSuffixes, formatExtensions } from '../core/index.ts';\n\nimport type { LoadTarget } from '../runtime/load.ts';\nimport type { TyfigoPluginOptions } from './shared.ts';\nimport type { TurbopackRuleCondition, TurbopackRuleConfigCollection } from 'next/dist/server/config-shared.js';\n\n// The loader sits next to this module: `loader.mjs` in the package, `loader.ts` when this runs from source.\nexport const loaderPath = fileURLToPath(new URL(`loader${extname(import.meta.url)}`, import.meta.url));\n\nexport const loaderOptions = (options: Omit<TyfigoPluginOptions, 'target'>, target: LoadTarget) => ({\n\ttarget,\n\t...(options.environment === undefined ? {} : { environment: options.environment }),\n\t...(options.runtime === undefined ? {} : { runtime: options.runtime }),\n});\n\nconst browser: TurbopackRuleCondition = { any: ['browser', 'edge-light'] };\n\n/**\n * The `turbopack.rules` globs for config files: `*.config.yaml` and the other suffixes match file names, and the `.config`\n * directory globs, which contain a `/`, match project-relative paths.\n */\nexport const turbopackGlobs = [\n\t...configSuffixes.map((suffix) => `*${suffix}`),\n\t...Object.keys(formatExtensions).map((extension) => `**/${configDirectory}/*${extension}`),\n];\n\n/**\n * `turbopack.rules` that load config files with the tyfigo loader: client and Edge code gets the browser module, Node.js\n * server code the bundled server module.\n */\nexport const turbopackRules = (\n\toptions: Omit<TyfigoPluginOptions, 'target'> = {},\n): Record<string, TurbopackRuleConfigCollection> =>\n\tObject.fromEntries(\n\t\tturbopackGlobs.map((glob) => [\n\t\t\tglob,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcondition: browser,\n\t\t\t\t\tloaders: [{ loader: loaderPath, options: loaderOptions(options, 'browser') }],\n\t\t\t\t\tas: '*.js',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcondition: { not: browser },\n\t\t\t\t\tloaders: [{ loader: loaderPath, options: loaderOptions(options, 'server') }],\n\t\t\t\t\tas: '*.js',\n\t\t\t\t},\n\t\t\t],\n\t\t]),\n\t);\n","import { spawn } from 'node:child_process';\nimport { once } from 'node:events';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport { loaderOptions, loaderPath, turbopackRules } from './turbopack.ts';\n\nimport { configPathPattern } from '../core/index.ts';\n\nimport type { TyfigoPluginOptions } from './shared.ts';\nimport type { NextConfig } from 'next';\n\nexport interface WithTyfigoOptions extends Omit<TyfigoPluginOptions, 'target'> {\n\t/**\n\t * `next build` type-checks without `--runExternalCode`, so TypeScript cannot type config imports. When this is on, Next's\n\t * own check is turned off and `tsc --noEmit --runExternalCode` runs after the production compile instead. Defaults to on\n\t * unless `typescript.ignoreBuildErrors` is set.\n\t */\n\treadonly typeCheck?: boolean | undefined;\n}\n\nconst tscPath = (projectDir: string) => {\n\tconst require = createRequire(join(projectDir, 'package.json'));\n\tconst manifest = require.resolve('typescript/package.json');\n\tconst { bin } = require(manifest) as { readonly bin: Readonly<Record<string, string>> };\n\treturn resolve(dirname(manifest), bin.tsc ?? 'bin/tsc');\n};\n\n/**\n * Runs `tsc --noEmit --runExternalCode` for the project's tsconfig, and rejects when it reports errors. Resolves without\n * checking when the tsconfig does not exist.\n */\nexport const typeCheck = async (projectDir: string, tsconfigPath = 'tsconfig.json'): Promise<void> => {\n\tconst project = resolve(projectDir, tsconfigPath);\n\tif (!existsSync(project)) return;\n\tconst tsc = spawn(process.execPath, [tscPath(projectDir), '--noEmit', '--runExternalCode', '--project', project], {\n\t\tcwd: projectDir,\n\t\tstdio: 'inherit',\n\t});\n\tconst [code] = (await once(tsc, 'exit')) as [number | null];\n\tif (code !== 0) throw new Error(`Type check failed: tsc --noEmit --runExternalCode --project ${project}`);\n};\n\n/**\n * Adds tyfigo to a Next.js config: a webpack rule and Turbopack rules for config imports, with the browser rule for client and\n * Edge code, and a type check that can read config imports.\n */\nexport const withTyfigo = (nextConfig: NextConfig = {}, options: WithTyfigoOptions = {}): NextConfig => {\n\tconst { typeCheck: check = !nextConfig.typescript?.ignoreBuildErrors, ...loader } = options;\n\tconst rule = (target: 'server' | 'browser') => ({\n\t\ttest: configPathPattern,\n\t\ttype: 'javascript/auto',\n\t\tuse: [{ loader: loaderPath, options: loaderOptions(loader, target) }],\n\t});\n\tconst config: NextConfig = {\n\t\t...nextConfig,\n\t\texperimental: { useTypeScriptCli: true, ...nextConfig.experimental },\n\t\tturbopack: {\n\t\t\t...nextConfig.turbopack,\n\t\t\trules: { ...turbopackRules(loader), ...nextConfig.turbopack?.rules },\n\t\t},\n\t\twebpack: (webpackConfig: { module: { rules: unknown[] } }, context) => {\n\t\t\tif (!context.isServer || context.nextRuntime === 'edge') {\n\t\t\t\twebpackConfig.module.rules.push(rule('browser'), {\n\t\t\t\t\ttest: /\\.[cm]?[jt]sx?$/u,\n\t\t\t\t\texclude: /[\\\\/]node_modules[\\\\/]/u,\n\t\t\t\t\tenforce: 'pre',\n\t\t\t\t\tuse: [{ loader: loaderPath }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\twebpackConfig.module.rules.push(\n\t\t\t\t\t{ ...rule('browser'), issuerLayer: 'ssr' },\n\t\t\t\t\t{ ...rule('server'), issuerLayer: { not: 'ssr' } },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn nextConfig.webpack ? nextConfig.webpack(webpackConfig, context) : webpackConfig;\n\t\t},\n\t};\n\tif (!check) return config;\n\n\treturn {\n\t\t...config,\n\t\ttypescript: { ...nextConfig.typescript, ignoreBuildErrors: true },\n\t\tcompiler: {\n\t\t\t...nextConfig.compiler,\n\t\t\trunAfterProductionCompile: async (metadata) => {\n\t\t\t\tawait nextConfig.compiler?.runAfterProductionCompile?.(metadata);\n\t\t\t\tawait typeCheck(metadata.projectDir, nextConfig.typescript?.tsconfigPath);\n\t\t\t},\n\t\t},\n\t};\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("rolldown").Plugin<any>;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=rolldown.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/rolldown.ts
3
3
  var rolldown_default = tyfigo.rolldown;
4
4
  export { rolldown_default as default };
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("rollup").Plugin<any>;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=rollup.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/rollup.ts
3
3
  var rollup_default = tyfigo.rollup;
4
4
  export { rollup_default as default };
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("unplugin").RsbuildPlugin;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=rsbuild.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/rsbuild.ts
3
3
  var rsbuild_default = tyfigo.rsbuild;
4
4
  export { rsbuild_default as default };
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("unplugin").RspackPluginInstance;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=rspack.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/rspack.ts
3
3
  var rspack_default = tyfigo.rspack;
4
4
  export { rspack_default as default };
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("vite").Plugin<any>;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=vite.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/vite.ts
3
3
  var vite_default = tyfigo.vite;
4
4
  export { vite_default as default };
@@ -1,5 +1,5 @@
1
- import { t as TyfigoPluginOptions } from "../shared-CZ44uwQq.mjs";
2
- import "../unplugin-AC_HM_T2.mjs";
1
+ import { t as TyfigoPluginOptions } from "../shared-B6Y3_kdn.mjs";
2
+ import "../unplugin-BYfqHkIE.mjs";
3
3
  declare const _default: (options?: TyfigoPluginOptions | undefined) => import("webpack").WebpackPluginInstance;
4
4
  export { type TyfigoPluginOptions, _default as default };
5
5
  //# sourceMappingURL=webpack.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as tyfigo } from "../unplugin-BQGm_bhA.mjs";
1
+ import { t as tyfigo } from "../unplugin-Bkc569Qw.mjs";
2
2
  // src/plugins/webpack.ts
3
3
  var webpack_default = tyfigo.webpack;
4
4
  export { webpack_default as default };
@@ -0,0 +1,86 @@
1
+ import { Effect } from "effect";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { readdirSync, statSync } from "node:fs";
4
+ // src/core/files.ts
5
+ /**
6
+ * The name of a directory whose files of a format extension are config files, `.config/app.yaml` for example.
7
+ */
8
+ const configDirectory = ".config";
9
+ /**
10
+ * Whether `path` is directly inside a `.config` directory.
11
+ */
12
+ const isInConfigDirectory = (path) => basename(dirname(path)) === configDirectory;
13
+ const isFile = (path) => Effect.sync(() => statSync(path, { throwIfNoEntry: false })?.isFile() ?? false);
14
+ /**
15
+ * The names of the entries in `directory`, or none when it cannot be read.
16
+ */
17
+ const listDirectory = (directory) => Effect.sync(() => {
18
+ try {
19
+ return readdirSync(directory);
20
+ } catch {
21
+ return [];
22
+ }
23
+ });
24
+ /**
25
+ * The nearest directory at or above `directory` that has a `package.json`.
26
+ */
27
+ const findProjectRoot = Effect.fn("findProjectRoot")(function* (directory) {
28
+ for (let current = directory;; current = dirname(current)) {
29
+ if (yield* isFile(join(current, "package.json"))) return current;
30
+ if (dirname(current) === current) return void 0;
31
+ }
32
+ });
33
+ /**
34
+ * The first existing `name` in `directories`.
35
+ */
36
+ const findFile = Effect.fn("findFile")(function* (directories, name) {
37
+ for (const directory of directories) {
38
+ const path = join(directory, name);
39
+ if (yield* isFile(path)) return path;
40
+ }
41
+ });
42
+ const withRoot = Effect.fn("withRoot")(function* (directory, inRoot = (root) => root) {
43
+ const root = yield* findProjectRoot(directory);
44
+ if (root === void 0) return [directory];
45
+ const second = inRoot(root);
46
+ return second === directory ? [directory] : [directory, second];
47
+ });
48
+ /**
49
+ * Where the local layers of a base file are searched: its directory, then the project root (the nearest directory with a
50
+ * `package.json`). For a file in a `.config` directory, the project root's `.config` directory.
51
+ */
52
+ const layerDirectories = Effect.fn("layerDirectories")(function* (baseFile) {
53
+ const directory = dirname(baseFile);
54
+ return yield* isInConfigDirectory(baseFile) ? withRoot(directory, (root) => join(root, configDirectory)) : withRoot(directory);
55
+ });
56
+ /**
57
+ * Where the `.env` files of a base file are searched: its directory, or the directory containing its `.config` directory, then
58
+ * the project root.
59
+ */
60
+ const envDirectories = Effect.fn("envDirectories")(function* (baseFile) {
61
+ const directory = dirname(baseFile);
62
+ return yield* withRoot(isInConfigDirectory(baseFile) ? dirname(directory) : directory);
63
+ });
64
+ // src/core/problems.ts
65
+ const problemAt = (source, file, start, length, code, message) => ({
66
+ file,
67
+ start,
68
+ length,
69
+ ...source.lineColumn(start),
70
+ message,
71
+ code
72
+ });
73
+ const fileProblem = (file, code, message) => ({
74
+ file,
75
+ start: 0,
76
+ length: 0,
77
+ line: 1,
78
+ column: 1,
79
+ message,
80
+ code
81
+ });
82
+ const formatProblem = (problem) => `${problem.file}:${problem.line}:${problem.column} - ${problem.message} (${problem.code})`;
83
+ const formatProblems = (problems) => problems.map(formatProblem).join("\n");
84
+ export { envDirectories as a, isFile as c, listDirectory as d, configDirectory as i, isInConfigDirectory as l, formatProblems as n, findFile as o, problemAt as r, findProjectRoot as s, fileProblem as t, layerDirectories as u };
85
+
86
+ //# sourceMappingURL=problems-DS_eJB6e.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"problems-DS_eJB6e.mjs","names":[],"sources":["../src/core/files.ts","../src/core/problems.ts"],"sourcesContent":["import { readdirSync, statSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\n\nimport { Effect } from 'effect';\n\n/**\n * The name of a directory whose files of a format extension are config files, `.config/app.yaml` for example.\n */\nexport const configDirectory = '.config';\n\n/**\n * Whether `path` is directly inside a `.config` directory.\n */\nexport const isInConfigDirectory = (path: string): boolean => basename(dirname(path)) === configDirectory;\n\nexport const isFile = (path: string): Effect.Effect<boolean> =>\n\tEffect.sync(() => statSync(path, { throwIfNoEntry: false })?.isFile() ?? false);\n\n/**\n * The names of the entries in `directory`, or none when it cannot be read.\n */\nexport const listDirectory = (directory: string): Effect.Effect<readonly string[]> =>\n\tEffect.sync(() => {\n\t\ttry {\n\t\t\treturn readdirSync(directory);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t});\n\n/**\n * The nearest directory at or above `directory` that has a `package.json`.\n */\nexport const findProjectRoot = Effect.fn('findProjectRoot')(function* (directory: string) {\n\tfor (let current = directory; ; current = dirname(current)) {\n\t\tif (yield* isFile(join(current, 'package.json'))) return current;\n\t\tif (dirname(current) === current) return undefined;\n\t}\n});\n\n/**\n * The first existing `name` in `directories`.\n */\nexport const findFile = Effect.fn('findFile')(function* (directories: readonly string[], name: string) {\n\tfor (const directory of directories) {\n\t\tconst path = join(directory, name);\n\t\tif (yield* isFile(path)) return path;\n\t}\n\treturn undefined;\n});\n\nconst withRoot = Effect.fn('withRoot')(function* (\n\tdirectory: string,\n\tinRoot: (root: string) => string = (root) => root,\n) {\n\tconst root = yield* findProjectRoot(directory);\n\tif (root === undefined) return [directory];\n\tconst second = inRoot(root);\n\treturn second === directory ? [directory] : [directory, second];\n});\n\n/**\n * Where the local layers of a base file are searched: its directory, then the project root (the nearest directory with a\n * `package.json`). For a file in a `.config` directory, the project root's `.config` directory.\n */\nexport const layerDirectories = Effect.fn('layerDirectories')(function* (baseFile: string) {\n\tconst directory = dirname(baseFile);\n\treturn yield* isInConfigDirectory(baseFile)\n\t\t? withRoot(directory, (root) => join(root, configDirectory))\n\t\t: withRoot(directory);\n});\n\n/**\n * Where the `.env` files of a base file are searched: its directory, or the directory containing its `.config` directory, then\n * the project root.\n */\nexport const envDirectories = Effect.fn('envDirectories')(function* (baseFile: string) {\n\tconst directory = dirname(baseFile);\n\treturn yield* withRoot(isInConfigDirectory(baseFile) ? dirname(directory) : directory);\n});\n","import type { SourceIndex } from './positions.ts';\n\nexport type ProblemCode =\n\t| 'parse-error'\n\t| 'duplicate-key'\n\t| 'file-not-found'\n\t| 'read-error'\n\t| 'unsupported-file'\n\t| 'missing-variable'\n\t| 'invalid-placeholder'\n\t| 'browser-placeholder'\n\t| 'placeholder-type'\n\t| 'unknown-key'\n\t| 'type-mismatch';\n\n/**\n * Something wrong with a config file. `start` and `length` are UTF-8 byte offsets, `line` and `column` are 1-based and\n * `column` counts UTF-16 code units.\n */\nexport interface Problem {\n\treadonly file: string;\n\treadonly start: number;\n\treadonly length: number;\n\treadonly line: number;\n\treadonly column: number;\n\treadonly message: string;\n\treadonly code: ProblemCode;\n}\n\nexport const problemAt = (\n\tsource: SourceIndex,\n\tfile: string,\n\tstart: number,\n\tlength: number,\n\tcode: ProblemCode,\n\tmessage: string,\n): Problem => ({ file, start, length, ...source.lineColumn(start), message, code });\n\nexport const fileProblem = (file: string, code: ProblemCode, message: string): Problem => ({\n\tfile,\n\tstart: 0,\n\tlength: 0,\n\tline: 1,\n\tcolumn: 1,\n\tmessage,\n\tcode,\n});\n\nexport const formatProblem = (problem: Problem): string =>\n\t`${problem.file}:${problem.line}:${problem.column} - ${problem.message} (${problem.code})`;\n\nexport const formatProblems = (problems: readonly Problem[]): string => problems.map(formatProblem).join('\\n');\n"],"mappings":";;;;;;;AAQA,MAAa,kBAAkB;;;;AAK/B,MAAa,uBAAuB,SAA0B,SAAS,QAAQ,IAAI,CAAC,MAAM;AAE1F,MAAa,UAAU,SACtB,OAAO,WAAW,SAAS,MAAM,EAAE,gBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,KAAK,KAAK;;;;AAK/E,MAAa,iBAAiB,cAC7B,OAAO,WAAW;CACjB,IAAI;EACH,OAAO,YAAY,SAAS;CAC7B,QAAQ;EACP,OAAO,CAAC;CACT;AACD,CAAC;;;;AAKF,MAAa,kBAAkB,OAAO,GAAG,iBAAiB,CAAC,CAAC,WAAW,WAAmB;CACzF,KAAK,IAAI,UAAU,YAAa,UAAU,QAAQ,OAAO,GAAG;EAC3D,IAAI,OAAO,OAAO,KAAK,SAAS,cAAc,CAAC,GAAG,OAAO;EACzD,IAAI,QAAQ,OAAO,MAAM,SAAS,OAAO,KAAA;CAC1C;AACD,CAAC;;;;AAKD,MAAa,WAAW,OAAO,GAAG,UAAU,CAAC,CAAC,WAAW,aAAgC,MAAc;CACtG,KAAK,MAAM,aAAa,aAAa;EACpC,MAAM,OAAO,KAAK,WAAW,IAAI;EACjC,IAAI,OAAO,OAAO,IAAI,GAAG,OAAO;CACjC;AAED,CAAC;AAED,MAAM,WAAW,OAAO,GAAG,UAAU,CAAC,CAAC,WACtC,WACA,UAAoC,SAAS,MAC5C;CACD,MAAM,OAAO,OAAO,gBAAgB,SAAS;CAC7C,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC,SAAS;CACzC,MAAM,SAAS,OAAO,IAAI;CAC1B,OAAO,WAAW,YAAY,CAAC,SAAS,IAAI,CAAC,WAAW,MAAM;AAC/D,CAAC;;;;;AAMD,MAAa,mBAAmB,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAAW,UAAkB;CAC1F,MAAM,YAAY,QAAQ,QAAQ;CAClC,OAAO,OAAO,oBAAoB,QAAQ,IACvC,SAAS,YAAY,SAAS,KAAK,MAAM,eAAe,CAAC,IACzD,SAAS,SAAS;AACtB,CAAC;;;;;AAMD,MAAa,iBAAiB,OAAO,GAAG,gBAAgB,CAAC,CAAC,WAAW,UAAkB;CACtF,MAAM,YAAY,QAAQ,QAAQ;CAClC,OAAO,OAAO,SAAS,oBAAoB,QAAQ,IAAI,QAAQ,SAAS,IAAI,SAAS;AACtF,CAAC;;AClDD,MAAa,aACZ,QACA,MACA,OACA,QACA,MACA,aACc;CAAE;CAAM;CAAO;CAAQ,GAAG,OAAO,WAAW,KAAK;CAAG;CAAS;AAAK;AAEjF,MAAa,eAAe,MAAc,MAAmB,aAA8B;CAC1F;CACA,OAAO;CACP,QAAQ;CACR,MAAM;CACN,QAAQ;CACR;CACA;AACD;AAEA,MAAa,iBAAiB,YAC7B,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ,OAAO,KAAK,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AAEzF,MAAa,kBAAkB,aAAyC,SAAS,IAAI,aAAa,CAAC,CAAC,KAAK,IAAI"}
package/dist/register.mjs CHANGED
@@ -1,15 +1,15 @@
1
- import { n as formatProblems } from "./problems-BNAqmOzL.mjs";
2
- import { n as parseConfigFileName } from "./formats-D_dKXoPf.mjs";
3
- import { t as load } from "./load-DxIjRpX6.mjs";
1
+ import { n as formatProblems } from "./problems-DS_eJB6e.mjs";
2
+ import { o as parseConfigPath } from "./formats-Bf8-iQw-.mjs";
3
+ import { t as load } from "./load-yFCdP4to.mjs";
4
4
  import { registerHooks } from "node:module";
5
- import { basename, extname } from "node:path";
5
+ import { extname } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  // src/register.ts
8
8
  const runtime = new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url).href;
9
9
  registerHooks({ load(url, context, nextLoad) {
10
10
  if (!url.startsWith("file:")) return nextLoad(url, context);
11
11
  const file = fileURLToPath(url);
12
- if (!parseConfigFileName(basename(file))) return nextLoad(url, context);
12
+ if (!parseConfigPath(file)) return nextLoad(url, context);
13
13
  const result = load(file, {
14
14
  target: "server",
15
15
  runtime
@@ -1 +1 @@
1
- {"version":3,"file":"register.mjs","names":[],"sources":["../src/register.ts"],"sourcesContent":["import { registerHooks } from 'node:module';\nimport { basename, extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { formatProblems, parseConfigFileName } from './core/index.ts';\nimport { load } from './runtime/index.ts';\n\n// The runtime next to this module, so it resolves from config files outside the dependency tree: `.ts` in this repo, `.mjs` once built.\nconst runtime = new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url).href;\n\nregisterHooks({\n\tload(url, context, nextLoad) {\n\t\tif (!url.startsWith('file:')) return nextLoad(url, context);\n\t\tconst file = fileURLToPath(url);\n\t\tif (!parseConfigFileName(basename(file))) return nextLoad(url, context);\n\n\t\tconst result = load(file, { target: 'server', runtime });\n\t\tif (result.problems.length > 0) throw new Error(`Invalid config ${file}\\n${formatProblems(result.problems)}`);\n\t\treturn { format: 'module', source: result.code, shortCircuit: true };\n\t},\n});\n"],"mappings":";;;;;;;AAQA,MAAM,UAAU,IAAI,IAAI,gBAAgB,QAAQ,YAAY,GAAG,KAAK,YAAY,GAAG,CAAC,CAAC;AAErF,cAAc,EACb,KAAK,KAAK,SAAS,UAAU;CAC5B,IAAI,CAAC,IAAI,WAAW,OAAO,GAAG,OAAO,SAAS,KAAK,OAAO;CAC1D,MAAM,OAAO,cAAc,GAAG;CAC9B,IAAI,CAAC,oBAAoB,SAAS,IAAI,CAAC,GAAG,OAAO,SAAS,KAAK,OAAO;CAEtE,MAAM,SAAS,KAAK,MAAM;EAAE,QAAQ;EAAU;CAAQ,CAAC;CACvD,IAAI,OAAO,SAAS,SAAS,GAAG,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAI,eAAe,OAAO,QAAQ,GAAG;CAC5G,OAAO;EAAE,QAAQ;EAAU,QAAQ,OAAO;EAAM,cAAc;CAAK;AACpE,EACD,CAAC"}
1
+ {"version":3,"file":"register.mjs","names":[],"sources":["../src/register.ts"],"sourcesContent":["import { registerHooks } from 'node:module';\nimport { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { formatProblems, parseConfigPath } from './core/index.ts';\nimport { load } from './runtime/index.ts';\n\n// The runtime next to this module, so it resolves from config files outside the dependency tree: `.ts` in this repo, `.mjs` once built.\nconst runtime = new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url).href;\n\nregisterHooks({\n\tload(url, context, nextLoad) {\n\t\tif (!url.startsWith('file:')) return nextLoad(url, context);\n\t\tconst file = fileURLToPath(url);\n\t\tif (!parseConfigPath(file)) return nextLoad(url, context);\n\n\t\tconst result = load(file, { target: 'server', runtime });\n\t\tif (result.problems.length > 0) throw new Error(`Invalid config ${file}\\n${formatProblems(result.problems)}`);\n\t\treturn { format: 'module', source: result.code, shortCircuit: true };\n\t},\n});\n"],"mappings":";;;;;;;AAQA,MAAM,UAAU,IAAI,IAAI,gBAAgB,QAAQ,YAAY,GAAG,KAAK,YAAY,GAAG,CAAC,CAAC;AAErF,cAAc,EACb,KAAK,KAAK,SAAS,UAAU;CAC5B,IAAI,CAAC,IAAI,WAAW,OAAO,GAAG,OAAO,SAAS,KAAK,OAAO;CAC1D,MAAM,OAAO,cAAc,GAAG;CAC9B,IAAI,CAAC,gBAAgB,IAAI,GAAG,OAAO,SAAS,KAAK,OAAO;CAExD,MAAM,SAAS,KAAK,MAAM;EAAE,QAAQ;EAAU;CAAQ,CAAC;CACvD,IAAI,OAAO,SAAS,SAAS,GAAG,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAI,eAAe,OAAO,QAAQ,GAAG;CAC5G,OAAO;EAAE,QAAQ;EAAU,QAAQ,OAAO;EAAM,cAAc;CAAK;AACpE,EACD,CAAC"}