@prisma-next/psl-parser 0.13.0-dev.2 → 0.13.0-dev.21

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.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { t as parsePslDocument } from "./parser-Dfi3Wfdq.mjs";
2
- import { ParsePslDocumentInput, ParsePslDocumentResult, PslAttribute, PslAttribute as PslAttribute$1, PslAttributeArgument, PslAttributeNamedArgument, PslAttributePositionalArgument, PslAttributeTarget, PslCompositeType, PslDefaultFunctionValue, PslDefaultLiteralValue, PslDefaultValue, PslDiagnostic, PslDiagnosticCode, PslDocumentAst, PslEnum, PslEnumValue, PslField, PslFieldAttribute, PslModel, PslModelAttribute, PslNamedTypeDeclaration, PslNamespace, PslPosition, PslSpan, PslTypeConstructorCall, PslTypesBlock } from "@prisma-next/framework-components/psl-ast";
2
+ import { ParsePslDocumentInput, ParsePslDocumentResult, PslAttribute, PslAttribute as PslAttribute$1, PslAttributeArgument, PslAttributeNamedArgument, PslAttributePositionalArgument, PslAttributeTarget, PslCompositeType, PslDefaultFunctionValue, PslDefaultLiteralValue, PslDefaultValue, PslDiagnostic, PslDiagnosticCode, PslDocumentAst, PslEnum, PslEnumValue, PslExtensionBlock, PslExtensionBlockAttribute, PslExtensionBlockAttributeArg, PslExtensionBlockParamBare, PslExtensionBlockParamList, PslExtensionBlockParamOption, PslExtensionBlockParamRef, PslExtensionBlockParamScalarValue, PslExtensionBlockParamValue, PslField, PslFieldAttribute, PslModel, PslModelAttribute, PslNamedTypeDeclaration, PslNamespace, PslPosition, PslSpan, PslTypeConstructorCall, PslTypesBlock, flatPslEnums, flatPslModels, namespacePslExtensionBlocks } from "@prisma-next/framework-components/psl-ast";
3
3
 
4
4
  //#region src/attribute-helpers.d.ts
5
5
  declare function getPositionalArgument(attribute: PslAttribute$1, index?: number): string | undefined;
6
6
  declare function parseQuotedStringLiteral(value: string): string | undefined;
7
7
  //#endregion
8
- export { type ParsePslDocumentInput, type ParsePslDocumentResult, type PslAttribute, type PslAttributeArgument, type PslAttributeNamedArgument, type PslAttributePositionalArgument, type PslAttributeTarget, type PslCompositeType, type PslDefaultFunctionValue, type PslDefaultLiteralValue, type PslDefaultValue, type PslDiagnostic, type PslDiagnosticCode, type PslDocumentAst, type PslEnum, type PslEnumValue, type PslField, type PslFieldAttribute, type PslModel, type PslModelAttribute, type PslNamedTypeDeclaration, type PslNamespace, type PslPosition, type PslSpan, type PslTypeConstructorCall, type PslTypesBlock, getPositionalArgument, parsePslDocument, parseQuotedStringLiteral };
8
+ export { type ParsePslDocumentInput, type ParsePslDocumentResult, type PslAttribute, type PslAttributeArgument, type PslAttributeNamedArgument, type PslAttributePositionalArgument, type PslAttributeTarget, type PslCompositeType, type PslDefaultFunctionValue, type PslDefaultLiteralValue, type PslDefaultValue, type PslDiagnostic, type PslDiagnosticCode, type PslDocumentAst, type PslEnum, type PslEnumValue, type PslExtensionBlock, type PslExtensionBlockAttribute, type PslExtensionBlockAttributeArg, type PslExtensionBlockParamBare, type PslExtensionBlockParamList, type PslExtensionBlockParamOption, type PslExtensionBlockParamRef, type PslExtensionBlockParamScalarValue, type PslExtensionBlockParamValue, type PslField, type PslFieldAttribute, type PslModel, type PslModelAttribute, type PslNamedTypeDeclaration, type PslNamespace, type PslPosition, type PslSpan, type PslTypeConstructorCall, type PslTypesBlock, flatPslEnums, flatPslModels, getPositionalArgument, namespacePslExtensionBlocks, parsePslDocument, parseQuotedStringLiteral };
9
9
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import { t as parsePslDocument } from "./parser-Cw_zV0M5.mjs";
1
+ import { t as parsePslDocument } from "./parser-Dw33hDIx.mjs";
2
+ import { flatPslEnums, flatPslModels, namespacePslExtensionBlocks } from "@prisma-next/framework-components/psl-ast";
2
3
  //#region src/attribute-helpers.ts
3
4
  function getPositionalArgument(attribute, index = 0) {
4
5
  return attribute.args.filter((arg) => arg.kind === "positional")[index]?.value;
@@ -9,6 +10,6 @@ function parseQuotedStringLiteral(value) {
9
10
  return match[2] ?? "";
10
11
  }
11
12
  //#endregion
12
- export { getPositionalArgument, parsePslDocument, parseQuotedStringLiteral };
13
+ export { flatPslEnums, flatPslModels, getPositionalArgument, namespacePslExtensionBlocks, parsePslDocument, parseQuotedStringLiteral };
13
14
 
14
15
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/attribute-helpers.ts"],"sourcesContent":["import type { PslAttribute } from '@prisma-next/framework-components/psl-ast';\n\nexport function getPositionalArgument(attribute: PslAttribute, index = 0): string | undefined {\n const entries = attribute.args.filter((arg) => arg.kind === 'positional');\n return entries[index]?.value;\n}\n\nexport function parseQuotedStringLiteral(value: string): string | undefined {\n const trimmed = value.trim();\n const match = trimmed.match(/^(['\"])(.*)\\1$/);\n if (!match) return undefined;\n return match[2] ?? '';\n}\n"],"mappings":";;AAEA,SAAgB,sBAAsB,WAAyB,QAAQ,GAAuB;CAE5F,OADgB,UAAU,KAAK,QAAQ,QAAQ,IAAI,SAAS,YAC/C,CAAC,CAAC,MAAM,EAAE;AACzB;AAEA,SAAgB,yBAAyB,OAAmC;CAE1E,MAAM,QADU,MAAM,KACF,CAAC,CAAC,MAAM,gBAAgB;CAC5C,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO,MAAM,MAAM;AACrB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/attribute-helpers.ts"],"sourcesContent":["import type { PslAttribute } from '@prisma-next/framework-components/psl-ast';\n\nexport function getPositionalArgument(attribute: PslAttribute, index = 0): string | undefined {\n const entries = attribute.args.filter((arg) => arg.kind === 'positional');\n return entries[index]?.value;\n}\n\nexport function parseQuotedStringLiteral(value: string): string | undefined {\n const trimmed = value.trim();\n const match = trimmed.match(/^(['\"])(.*)\\1$/);\n if (!match) return undefined;\n return match[2] ?? '';\n}\n"],"mappings":";;;AAEA,SAAgB,sBAAsB,WAAyB,QAAQ,GAAuB;CAE5F,OADgB,UAAU,KAAK,QAAQ,QAAQ,IAAI,SAAS,YAC/C,CAAC,CAAC,MAAM,EAAE;AACzB;AAEA,SAAgB,yBAAyB,OAAmC;CAE1E,MAAM,QADU,MAAM,KACF,CAAC,CAAC,MAAM,gBAAgB;CAC5C,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO,MAAM,MAAM;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"parser-Dfi3Wfdq.d.mts","names":[],"sources":["../src/parser.ts"],"mappings":";;;iBAkEgB,gBAAA,CAAiB,KAAA,EAAO,qBAAA,GAAwB,sBAAsB"}
1
+ {"version":3,"file":"parser-Dfi3Wfdq.d.mts","names":[],"sources":["../src/parser.ts"],"mappings":";;;iBAoEgB,gBAAA,CAAiB,KAAA,EAAO,qBAAA,GAAwB,sBAAsB"}
@@ -1,6 +1,6 @@
1
+ import { UNSPECIFIED_PSL_NAMESPACE_ID, makePslNamespace, makePslNamespaceEntries, namespacePslExtensionBlocks, validateExtensionBlock } from "@prisma-next/framework-components/psl-ast";
1
2
  import { isAuthoringPslBlockDescriptor } from "@prisma-next/framework-components/authoring";
2
3
  import { emptyCodecLookup } from "@prisma-next/framework-components/codec";
3
- import { UNSPECIFIED_PSL_NAMESPACE_ID, makePslNamespace, makePslNamespaceEntries, namespacePslExtensionBlocks, validateExtensionBlock } from "@prisma-next/framework-components/psl-ast";
4
4
  import { ifDefined } from "@prisma-next/utils/defined";
5
5
  //#region src/parser.ts
6
6
  const SCALAR_TYPES = new Set([
@@ -1070,55 +1070,135 @@ function lookupExtensionBlockDescriptor(namespace, keyword) {
1070
1070
  }
1071
1071
  /**
1072
1072
  * Reads an extension block body generically, driven by the descriptor's
1073
- * `parameters` map. Each `key = <rhs>` line in the body is matched against
1074
- * a declared parameter and the RHS is captured per the parameter's kind:
1073
+ * `parameters` map. Each body line is one of:
1075
1074
  *
1076
- * - `ref` → the bareword identifier token (`PslExtensionBlockParamRef`)
1077
- * - `value` → the raw RHS text verbatim (`PslExtensionBlockParamScalarValue`)
1078
- * - `option` the chosen bareword token (`PslExtensionBlockParamOption`)
1079
- * - `list` → bracketed `[a, b, …]` list, each element captured per `of`
1080
- * (`PslExtensionBlockParamList`)
1075
+ * - `@@name(args…)` a block attribute, captured in `blockAttributes`
1076
+ * - `key = <rhs>` a parameter entry, captured in `parameters` per descriptor
1077
+ * - `key` a bare-identifier entry (no `= value`), captured as `kind:'bare'`
1081
1078
  *
1082
- * No validation runs here (unknown key, missing required, codec acceptance,
1083
- * option-in-set, ref resolution). A body line that is not `key = value`
1084
- * shaped emits a `PSL_INVALID_EXTENSION_BLOCK_MEMBER` parse diagnostic.
1079
+ * Duplicate parameter keys emit `PSL_EXTENSION_DUPLICATE_PARAMETER`; the first
1080
+ * occurrence wins. `@@` attribute lines are not validated here (name or args);
1081
+ * that is a concern of the consuming interpreter.
1085
1082
  */
1086
1083
  function parseExtensionBlock(context, descriptor, blockName, keywordLineIndex, bounds) {
1087
1084
  const parameters = {};
1085
+ const blockAttributes = [];
1088
1086
  for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {
1089
1087
  const line = stripInlineComment(context.lines[lineIndex] ?? "").trim();
1090
1088
  if (line.length === 0) continue;
1089
+ if (line.startsWith("@@")) {
1090
+ const attr = parseExtensionBlockAttribute(context, line, lineIndex);
1091
+ if (attr !== void 0) blockAttributes.push(attr);
1092
+ continue;
1093
+ }
1091
1094
  const assignMatch = line.match(/^([A-Za-z_]\w*)\s*=\s*(.+)$/);
1092
- if (!assignMatch) {
1093
- pushDiagnostic(context, {
1094
- code: "PSL_INVALID_EXTENSION_BLOCK_MEMBER",
1095
- message: `Invalid extension block body line "${line}"; expected "key = value"`,
1095
+ if (assignMatch) {
1096
+ const key = assignMatch[1] ?? "";
1097
+ const rhsRaw = (assignMatch[2] ?? "").trim();
1098
+ if (Object.hasOwn(parameters, key)) {
1099
+ pushDiagnostic(context, {
1100
+ code: "PSL_EXTENSION_DUPLICATE_PARAMETER",
1101
+ message: `Duplicate parameter "${key}" in "${descriptor.keyword}" block "${blockName}"; first occurrence wins`,
1102
+ span: createTrimmedLineSpan(context, lineIndex)
1103
+ });
1104
+ continue;
1105
+ }
1106
+ const paramDescriptor = descriptor.parameters[key];
1107
+ if (paramDescriptor === void 0) parameters[key] = {
1108
+ kind: "value",
1109
+ raw: rhsRaw,
1096
1110
  span: createTrimmedLineSpan(context, lineIndex)
1097
- });
1111
+ };
1112
+ else {
1113
+ const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);
1114
+ if (captured !== void 0) parameters[key] = captured;
1115
+ }
1098
1116
  continue;
1099
1117
  }
1100
- const key = assignMatch[1] ?? "";
1101
- const rhsRaw = (assignMatch[2] ?? "").trim();
1102
- const paramDescriptor = descriptor.parameters[key];
1103
- if (paramDescriptor === void 0) {
1118
+ const bareMatch = line.match(/^([A-Za-z_]\w*)$/);
1119
+ if (bareMatch) {
1120
+ const key = bareMatch[1] ?? "";
1121
+ if (!descriptor.variadicParameters) {
1122
+ pushDiagnostic(context, {
1123
+ code: "PSL_INVALID_EXTENSION_BLOCK_MEMBER",
1124
+ message: `Invalid extension block body line "${line}"; expected "key = value" or "@@attribute"`,
1125
+ span: createTrimmedLineSpan(context, lineIndex)
1126
+ });
1127
+ continue;
1128
+ }
1129
+ if (Object.hasOwn(descriptor.parameters, key)) {
1130
+ pushDiagnostic(context, {
1131
+ code: "PSL_INVALID_EXTENSION_BLOCK_MEMBER",
1132
+ message: `Parameter "${key}" in "${descriptor.keyword}" block "${blockName}" is declared in the descriptor and must be supplied as "${key} = value"`,
1133
+ span: createTrimmedLineSpan(context, lineIndex)
1134
+ });
1135
+ continue;
1136
+ }
1137
+ if (Object.hasOwn(parameters, key)) {
1138
+ pushDiagnostic(context, {
1139
+ code: "PSL_EXTENSION_DUPLICATE_PARAMETER",
1140
+ message: `Duplicate parameter "${key}" in "${descriptor.keyword}" block "${blockName}"; first occurrence wins`,
1141
+ span: createTrimmedLineSpan(context, lineIndex)
1142
+ });
1143
+ continue;
1144
+ }
1104
1145
  parameters[key] = {
1105
- kind: "value",
1106
- raw: rhsRaw,
1146
+ kind: "bare",
1107
1147
  span: createTrimmedLineSpan(context, lineIndex)
1108
1148
  };
1109
1149
  continue;
1110
1150
  }
1111
- const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);
1112
- if (captured !== void 0) parameters[key] = captured;
1151
+ pushDiagnostic(context, {
1152
+ code: "PSL_INVALID_EXTENSION_BLOCK_MEMBER",
1153
+ message: `Invalid extension block body line "${line}"; expected "key = value", "key", or "@@attribute"`,
1154
+ span: createTrimmedLineSpan(context, lineIndex)
1155
+ });
1113
1156
  }
1114
1157
  return {
1115
1158
  kind: descriptor.discriminator,
1116
1159
  name: blockName,
1117
1160
  parameters,
1161
+ blockAttributes,
1118
1162
  span: createLineRangeSpan(context, keywordLineIndex, bounds.endLine)
1119
1163
  };
1120
1164
  }
1121
1165
  /**
1166
+ * Parses a `@@name(args…)` block-attribute line inside an extension block
1167
+ * using the shared block-attribute tokeniser (`extractAttributeTokensWithSpans`
1168
+ * + `parseAttributeToken`). Returns undefined (and emits a diagnostic) on
1169
+ * malformed syntax.
1170
+ */
1171
+ function parseExtensionBlockAttribute(context, line, lineIndex) {
1172
+ const tokenParse = extractAttributeTokensWithSpans(context, lineIndex, line, firstNonWhitespaceColumn(context.lines[lineIndex] ?? ""));
1173
+ if (!tokenParse.ok || tokenParse.tokens.length !== 1) {
1174
+ pushDiagnostic(context, {
1175
+ code: "PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE",
1176
+ message: `Invalid extension block attribute "${line}"`,
1177
+ span: createTrimmedLineSpan(context, lineIndex)
1178
+ });
1179
+ return;
1180
+ }
1181
+ const token = tokenParse.tokens[0];
1182
+ if (!token) return;
1183
+ const parsed = parseAttributeToken(context, {
1184
+ token: token.text,
1185
+ target: "model",
1186
+ lineIndex,
1187
+ span: token.span
1188
+ });
1189
+ if (!parsed) return;
1190
+ const args = parsed.args.filter((a) => a.kind === "positional").map((a) => ({
1191
+ kind: "positional",
1192
+ value: a.value,
1193
+ span: a.span
1194
+ }));
1195
+ return {
1196
+ name: parsed.name,
1197
+ args,
1198
+ span: parsed.span
1199
+ };
1200
+ }
1201
+ /**
1122
1202
  * Captures a single parameter RHS string according to the declared parameter
1123
1203
  * kind. Returns `undefined` and pushes a diagnostic only if the syntax is
1124
1204
  * genuinely malformed (e.g. a `list` with no opening bracket). Value
@@ -1173,4 +1253,4 @@ function captureParamRhs(context, lineIndex, rhs, param) {
1173
1253
  //#endregion
1174
1254
  export { parsePslDocument as t };
1175
1255
 
1176
- //# sourceMappingURL=parser-Cw_zV0M5.mjs.map
1256
+ //# sourceMappingURL=parser-Dw33hDIx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser-Dw33hDIx.mjs","names":[],"sources":["../src/parser.ts"],"sourcesContent":["import type {\n AuthoringPslBlockDescriptor,\n AuthoringPslBlockDescriptorNamespace,\n} from '@prisma-next/framework-components/authoring';\nimport { isAuthoringPslBlockDescriptor } from '@prisma-next/framework-components/authoring';\nimport { emptyCodecLookup } from '@prisma-next/framework-components/codec';\nimport type {\n ParsePslDocumentInput,\n ParsePslDocumentResult,\n PslAttribute,\n PslAttributeArgument,\n PslAttributeTarget,\n PslCompositeType,\n PslDiagnostic,\n PslDiagnosticCode,\n PslDocumentAst,\n PslEnum,\n PslEnumValue,\n PslExtensionBlock,\n PslExtensionBlockAttribute,\n PslExtensionBlockAttributeArg,\n PslExtensionBlockParamValue,\n PslField,\n PslFieldAttribute,\n PslModel,\n PslModelAttribute,\n PslNamedTypeDeclaration,\n PslNamespace,\n PslPosition,\n PslSpan,\n PslTypeConstructorCall,\n PslTypesBlock,\n} from '@prisma-next/framework-components/psl-ast';\nimport {\n makePslNamespace,\n makePslNamespaceEntries,\n namespacePslExtensionBlocks,\n UNSPECIFIED_PSL_NAMESPACE_ID,\n validateExtensionBlock,\n} from '@prisma-next/framework-components/psl-ast';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\nconst SCALAR_TYPES = new Set([\n 'String',\n 'Boolean',\n 'Int',\n 'BigInt',\n 'Float',\n 'Decimal',\n 'DateTime',\n 'Json',\n 'Bytes',\n]);\n\ninterface BlockBounds {\n readonly startLine: number;\n readonly endLine: number;\n readonly closed: boolean;\n}\n\ninterface ParserContext {\n readonly schema: string;\n readonly sourceId: string;\n readonly lines: readonly string[];\n readonly lineOffsets: readonly number[];\n readonly diagnostics: PslDiagnostic[];\n}\n\nexport function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocumentResult {\n const normalizedSchema = input.schema.replaceAll('\\r\\n', '\\n');\n const lines = normalizedSchema.split('\\n');\n const lineOffsets = computeLineOffsets(normalizedSchema);\n const diagnostics: PslDiagnostic[] = [];\n const context: ParserContext = {\n schema: normalizedSchema,\n sourceId: input.sourceId,\n lines,\n lineOffsets,\n diagnostics,\n };\n\n interface NamespaceAccumulator {\n name: string;\n models: PslModel[];\n enums: PslEnum[];\n compositeTypes: PslCompositeType[];\n extensionBlocks: PslExtensionBlock[];\n span: PslSpan | undefined;\n }\n\n const namespaceOrder: string[] = [];\n const namespacesByName = new Map<string, NamespaceAccumulator>();\n const getOrCreateNamespace = (\n name: string,\n spanIfNew: PslSpan | undefined,\n ): NamespaceAccumulator => {\n let acc = namespacesByName.get(name);\n if (!acc) {\n acc = {\n name,\n models: [],\n enums: [],\n compositeTypes: [],\n extensionBlocks: [],\n span: spanIfNew,\n };\n namespacesByName.set(name, acc);\n namespaceOrder.push(name);\n }\n return acc;\n };\n\n let typesBlock: PslTypesBlock | undefined;\n const pslBlockNamespace: AuthoringPslBlockDescriptorNamespace = input.pslBlockDescriptors ?? {};\n\n // Walk a contiguous range of lines, routing top-level declarations into the\n // active namespace bucket. Called once for the whole document and once per\n // `namespace { … }` block body; nested `namespace { … }` or `types { … }`\n // blocks inside a namespace body are rejected with a diagnostic.\n const parseBody = (\n startLine: number,\n endLineExclusive: number,\n currentNamespaceName: string,\n isInsideNamespace: boolean,\n ): void => {\n let lineIndex = startLine;\n while (lineIndex < endLineExclusive) {\n const rawLine = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(rawLine).trim();\n if (line.length === 0) {\n lineIndex += 1;\n continue;\n }\n\n const modelMatch = line.match(/^model\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (modelMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = modelMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.models.push(parseModelBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const enumMatch = line.match(/^enum\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (enumMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = enumMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.enums.push(parseEnumBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const compositeTypeMatch = line.match(/^type\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (compositeTypeMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = compositeTypeMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.compositeTypes.push(parseCompositeTypeBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const namespaceMatch = line.match(/^namespace\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (namespaceMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = namespaceMatch[1] ?? '';\n if (isInsideNamespace) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message: `Recursive \"namespace ${name}\" block is not allowed; namespace blocks may not nest`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (name === UNSPECIFIED_PSL_NAMESPACE_ID) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message: `Namespace name \"${UNSPECIFIED_PSL_NAMESPACE_ID}\" is reserved for the parser-synthesised bucket for top-level declarations`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (name.length > 0) {\n getOrCreateNamespace(name, createTrimmedLineSpan(context, lineIndex));\n parseBody(bounds.startLine + 1, bounds.endLine, name, true);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n if (/^types\\s*\\{$/.test(line)) {\n const bounds = findBlockBounds(context, lineIndex);\n if (isInsideNamespace) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message:\n '`types` blocks must be declared at the document top level, not inside a namespace block',\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (typesBlock !== undefined) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: 'Only one top-level `types` block is allowed per document',\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else {\n typesBlock = parseTypesBlock(context, bounds);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const extensionBlockMatch = line.match(/^([A-Za-z_]\\w*)\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (extensionBlockMatch) {\n const keyword = extensionBlockMatch[1] ?? '';\n const blockName = extensionBlockMatch[2] ?? '';\n const descriptor = lookupExtensionBlockDescriptor(pslBlockNamespace, keyword);\n if (descriptor) {\n const bounds = findBlockBounds(context, lineIndex);\n if (blockName.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n const node = parseExtensionBlock(context, descriptor, blockName, lineIndex, bounds);\n acc.extensionBlocks.push(node);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n }\n\n if (line.includes('{')) {\n const blockName = line.split(/\\s+/)[0] ?? 'block';\n pushDiagnostic(context, {\n code: 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK',\n message: `Unsupported top-level block \"${blockName}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n const bounds = findBlockBounds(context, lineIndex);\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n pushDiagnostic(context, {\n code: 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK',\n message: `Unsupported top-level declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n lineIndex += 1;\n }\n };\n\n parseBody(0, lines.length, UNSPECIFIED_PSL_NAMESPACE_ID, false);\n\n // Named-type validation: types are document-scoped (one block, outside any\n // namespace), so collision checks compare named-type names against every\n // model/enum/composite-type in every namespace.\n const allModels: PslModel[] = [];\n const allEnums: PslEnum[] = [];\n const allCompositeTypes: PslCompositeType[] = [];\n for (const name of namespaceOrder) {\n const acc = namespacesByName.get(name);\n if (!acc) continue;\n allModels.push(...acc.models);\n allEnums.push(...acc.enums);\n allCompositeTypes.push(...acc.compositeTypes);\n }\n\n const namedTypeNames = new Set(\n (typesBlock?.declarations ?? []).map((declaration) => declaration.name),\n );\n const modelNames = new Set(allModels.map((model) => model.name));\n const enumNames = new Set(allEnums.map((enumBlock) => enumBlock.name));\n const compositeTypeNames = new Set(allCompositeTypes.map((ct) => ct.name));\n for (const declaration of typesBlock?.declarations ?? []) {\n if (SCALAR_TYPES.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with scalar type \"${declaration.name}\"`,\n span: declaration.span,\n });\n continue;\n }\n if (modelNames.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with model name \"${declaration.name}\"`,\n span: declaration.span,\n });\n continue;\n }\n if (enumNames.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with enum name \"${declaration.name}\"`,\n span: declaration.span,\n });\n }\n }\n\n const documentSpan: PslSpan = {\n start: createPosition(context, 0, 0),\n end: createPosition(\n context,\n Math.max(lines.length - 1, 0),\n (lines[Math.max(lines.length - 1, 0)] ?? '').length,\n ),\n };\n\n const namespaces: PslNamespace[] = [];\n for (const name of namespaceOrder) {\n const acc = namespacesByName.get(name);\n if (!acc) continue;\n // Drop the synthesised __unspecified__ entry when it ended up empty (e.g.\n // every declaration in the document lived inside an explicit\n // `namespace { … }` block). Keeping a phantom bucket would force every\n // downstream consumer to special-case \"namespace with no members\".\n if (\n name === UNSPECIFIED_PSL_NAMESPACE_ID &&\n acc.models.length === 0 &&\n acc.enums.length === 0 &&\n acc.compositeTypes.length === 0 &&\n acc.extensionBlocks.length === 0\n ) {\n continue;\n }\n const normalizedModels = acc.models.map((model) => ({\n ...model,\n fields: model.fields.map((field) => {\n if (!namedTypeNames.has(field.typeName)) {\n return field;\n }\n const hasRelationAttribute = field.attributes.some(\n (attribute) => attribute.name === 'relation',\n );\n if (\n hasRelationAttribute ||\n modelNames.has(field.typeName) ||\n enumNames.has(field.typeName) ||\n compositeTypeNames.has(field.typeName) ||\n SCALAR_TYPES.has(field.typeName)\n ) {\n return field;\n }\n return {\n ...field,\n typeRef: field.typeName,\n };\n }),\n }));\n namespaces.push(\n makePslNamespace({\n kind: 'namespace',\n name,\n entries: makePslNamespaceEntries(\n normalizedModels,\n acc.enums,\n acc.compositeTypes,\n acc.extensionBlocks,\n ),\n span: acc.span ?? documentSpan,\n }),\n );\n }\n\n // Validate extension blocks with the generic validator after the full\n // AST is assembled. The validator needs all namespaces for ref resolution.\n // It runs whenever pslBlockDescriptors are registered — codecLookup falls\n // back to emptyCodecLookup when not provided, which rejects value-kind\n // parameters with unknown codecs. Callers with value parameters should\n // always supply a codecLookup.\n if (Object.keys(pslBlockNamespace).length > 0) {\n const codecLookup = input.codecLookup ?? emptyCodecLookup;\n // Build a discriminator → descriptor reverse map from the descriptor\n // namespace. The parser keyed by keyword; the validator resolves by\n // node.kind (= discriminator) so we need the reverse direction.\n const descriptorByDiscriminator = new Map<string, AuthoringPslBlockDescriptor>();\n for (const value of Object.values(pslBlockNamespace)) {\n if (isAuthoringPslBlockDescriptor(value)) {\n descriptorByDiscriminator.set(value.discriminator, value);\n }\n }\n for (const ns of namespaces) {\n // Collect extension blocks from entries using the canonical helper, then\n // filter to only those whose discriminator is registered in the namespace.\n for (const block of namespacePslExtensionBlocks(ns)) {\n const descriptor = descriptorByDiscriminator.get(block.kind);\n if (descriptor === undefined) {\n continue;\n }\n const blockDiagnostics = validateExtensionBlock(\n block,\n descriptor,\n input.sourceId,\n codecLookup,\n {\n ownerNamespace: ns,\n allNamespaces: namespaces,\n },\n );\n diagnostics.push(...blockDiagnostics);\n }\n }\n }\n\n const ast: PslDocumentAst = {\n kind: 'document',\n sourceId: input.sourceId,\n namespaces,\n ...ifDefined('types', typesBlock),\n span: documentSpan,\n };\n\n return {\n ast,\n diagnostics,\n ok: diagnostics.length === 0,\n };\n}\n\nfunction parseModelBlock(context: ParserContext, name: string, bounds: BlockBounds): PslModel {\n const fields: PslField[] = [];\n const attributes: PslModelAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseModelAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n const field = parseField(context, line, lineIndex);\n if (field) {\n fields.push(field);\n }\n }\n\n return {\n kind: 'model',\n name,\n fields,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseCompositeTypeBlock(\n context: ParserContext,\n name: string,\n bounds: BlockBounds,\n): PslCompositeType {\n const fields: PslField[] = [];\n const attributes: PslAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseModelAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n const field = parseField(context, line, lineIndex);\n if (field) {\n fields.push(field);\n }\n }\n\n return {\n kind: 'compositeType',\n name,\n fields,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseEnumBlock(context: ParserContext, name: string, bounds: BlockBounds): PslEnum {\n const values: PslEnumValue[] = [];\n const attributes: PslAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseEnumAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n // An enum member line is the bare member identifier, optionally followed\n // by a `@map(\"storage-label\")` attribute. The map attribute lets the\n // printer round-trip enum values whose original storage label is not a\n // valid PSL identifier (e.g. PostgreSQL enum labels with hyphens).\n const valueMatch = line.match(/^([A-Za-z_]\\w*)(?:\\s+@map\\(\\s*\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\))?$/);\n if (!valueMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const mapName = valueMatch[2] !== undefined ? unescapePslString(valueMatch[2]) : undefined;\n\n values.push({\n kind: 'enumValue',\n name: valueMatch[1] ?? '',\n ...(mapName !== undefined ? { mapName } : {}),\n span: createTrimmedLineSpan(context, lineIndex),\n });\n }\n\n return {\n kind: 'enum',\n name,\n values,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\n/**\n * Decode PSL escape sequences (`\\\\`, `\\\"`, `\\'`, `\\n`, `\\r`) inside a\n * quoted-literal body. The argument is the body of the literal with the\n * surrounding quotes already stripped by the caller. Mirrors the inverse\n * helper in `@prisma-next/psl-printer`'s `escapePslString` so a string\n * round-trips parser → printer → parser unchanged.\n */\nfunction unescapePslString(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n if (ch !== 0x5c /* '\\\\' */ || i + 1 >= value.length) {\n result += value[i];\n continue;\n }\n const next = value[i + 1];\n if (next === '\\\\' || next === '\"' || next === \"'\") {\n result += next;\n } else if (next === 'n') {\n result += '\\n';\n } else if (next === 'r') {\n result += '\\r';\n } else {\n result += '\\\\';\n result += next;\n }\n i++;\n }\n return result;\n}\n\nfunction parseTypesBlock(context: ParserContext, bounds: BlockBounds): PslTypesBlock {\n const declarations: PslNamedTypeDeclaration[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const lineWithoutComment = stripInlineComment(raw);\n const line = lineWithoutComment.trim();\n if (line.length === 0) {\n continue;\n }\n\n const declarationMatch = line.match(/^([A-Za-z_]\\w*)\\s*=\\s*(.+)$/);\n if (!declarationMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Invalid types declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const declarationName = declarationMatch[1] ?? '';\n const trimmedStartColumn = firstNonWhitespaceColumn(raw);\n const declarationValue = (declarationMatch[2] ?? '').trim();\n const valueOffset = line.indexOf(declarationValue);\n const declarationValueColumn = trimmedStartColumn + Math.max(valueOffset, 0);\n\n const typeAndAttributeSplit = splitTypeAndAttributes(declarationValue);\n const typeSource = typeAndAttributeSplit.typeSource.trim();\n const attributeSource = typeAndAttributeSplit.attributeSource.trimStart();\n const leadingAttributeWhitespace =\n typeAndAttributeSplit.attributeSource.length - attributeSource.length;\n\n const typeConstructor = parseTypeConstructorCall(context, {\n declarationValue: typeSource,\n lineIndex,\n startColumn: declarationValueColumn,\n invalidCode: 'PSL_INVALID_TYPES_MEMBER',\n invalidMessage: (value) => `Invalid types declaration \"${value}\"`,\n });\n if (typeConstructor === 'malformed') {\n continue;\n }\n\n const attributeParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n attributeSource,\n declarationValueColumn + typeAndAttributeSplit.attributeOffset + leadingAttributeWhitespace,\n );\n if (!attributeParse.ok) {\n continue;\n }\n const attributes = attributeParse.tokens\n .map((token) =>\n parseAttributeToken(context, {\n token: token.text,\n target: 'namedType',\n lineIndex,\n span: token.span,\n }),\n )\n .filter((attribute): attribute is PslAttribute => Boolean(attribute));\n\n if (typeConstructor) {\n declarations.push({\n kind: 'namedType',\n name: declarationName,\n typeConstructor,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const baseTypeMatch = typeSource.match(/^([A-Za-z_]\\w*)$/);\n if (!baseTypeMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Invalid types declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const baseType = baseTypeMatch[1] ?? '';\n\n declarations.push({\n kind: 'namedType',\n name: declarationName,\n baseType,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n }\n\n return {\n kind: 'types',\n declarations,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseTypeConstructorCall(\n context: ParserContext,\n input: {\n readonly declarationValue: string;\n readonly lineIndex: number;\n readonly startColumn: number;\n readonly invalidCode: PslDiagnosticCode;\n readonly invalidMessage: (value: string) => string;\n },\n): PslTypeConstructorCall | 'malformed' | undefined {\n const value = input.declarationValue.trim();\n const constructorMatch = value.match(\n /^([A-Za-z_][A-Za-z0-9_-]*(?:\\.[A-Za-z_][A-Za-z0-9_-]*)*)\\s*\\(/,\n );\n if (!constructorMatch) {\n return undefined;\n }\n\n // constructorMatch already required `(`; openParen is guaranteed ≥ 0.\n const openParen = value.indexOf('(');\n const closeParen = value.lastIndexOf(')');\n\n if (closeParen !== value.length - 1) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidMessage(value),\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n });\n return 'malformed';\n }\n\n const constructorPath = constructorMatch[1] ?? '';\n\n const argsRaw = value.slice(openParen + 1, closeParen);\n const args = parseArgumentList(context, {\n argsRaw,\n argsOffset: input.startColumn + openParen + 1,\n lineIndex: input.lineIndex,\n token: value,\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n invalidCode: input.invalidCode,\n invalidEmptyArgumentMessage: `Invalid empty argument in type constructor \"${value}\"`,\n invalidNamedArgumentMessage: (part) =>\n `Invalid named argument syntax \"${part}\" in type constructor \"${value}\"`,\n });\n if (!args) {\n return 'malformed';\n }\n\n return {\n kind: 'typeConstructor',\n path: constructorPath.split('.'),\n args,\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n };\n}\n\nfunction parseModelAttribute(\n context: ParserContext,\n line: string,\n lineIndex: number,\n): PslModelAttribute | undefined {\n const rawLine = context.lines[lineIndex] ?? '';\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n line,\n firstNonWhitespaceColumn(rawLine),\n );\n if (!tokenParse.ok || tokenParse.tokens.length !== 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid model attribute syntax \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n const token = tokenParse.tokens[0];\n if (!token) {\n return undefined;\n }\n return parseAttributeToken(context, {\n token: token.text,\n target: 'model',\n lineIndex,\n span: token.span,\n });\n}\n\nfunction parseEnumAttribute(\n context: ParserContext,\n line: string,\n lineIndex: number,\n): PslAttribute | undefined {\n const rawLine = context.lines[lineIndex] ?? '';\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n line,\n firstNonWhitespaceColumn(rawLine),\n );\n if (!tokenParse.ok || tokenParse.tokens.length !== 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n const token = tokenParse.tokens[0];\n if (!token) {\n return undefined;\n }\n const parsed = parseAttributeToken(context, {\n token: token.text,\n target: 'enum',\n lineIndex,\n span: token.span,\n });\n if (!parsed) {\n return undefined;\n }\n if (parsed.name !== 'map') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n return parsed;\n}\n\nfunction parseField(context: ParserContext, line: string, lineIndex: number): PslField | undefined {\n const fieldMatch = line.match(/^([A-Za-z_]\\w*)(\\s+)(.+)$/);\n if (!fieldMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n\n const fieldName = fieldMatch[1] ?? '';\n const separator = fieldMatch[2] ?? '';\n const remainder = fieldMatch[3] ?? '';\n const typeAndAttributeSplit = splitTypeAndAttributes(remainder);\n const rawTypeSource = typeAndAttributeSplit.typeSource.trim();\n const attributePart = typeAndAttributeSplit.attributeSource;\n const optional = rawTypeSource.endsWith('?');\n const typeSourceWithoutOptional = optional ? rawTypeSource.slice(0, -1).trimEnd() : rawTypeSource;\n const list = typeSourceWithoutOptional.endsWith('[]');\n const baseTypeSource = list\n ? typeSourceWithoutOptional.slice(0, -2).trimEnd()\n : typeSourceWithoutOptional;\n const rawLine = context.lines[lineIndex] ?? '';\n const trimmedStartColumn = firstNonWhitespaceColumn(rawLine);\n const typeStartColumn = trimmedStartColumn + fieldName.length + separator.length;\n\n const typeConstructor = parseTypeConstructorCall(context, {\n declarationValue: baseTypeSource,\n lineIndex,\n startColumn: typeStartColumn,\n invalidCode: 'PSL_INVALID_MODEL_MEMBER',\n invalidMessage: (value) => `Invalid field type constructor \"${value}\"`,\n });\n if (typeConstructor === 'malformed') {\n return undefined;\n }\n\n let typeName: string;\n let typeNamespaceId: string | undefined;\n let typeContractSpaceId: string | undefined;\n\n if (typeConstructor) {\n typeName = typeConstructor.path.join('.');\n } else {\n // Detect the colon-prefix cross-contract-space form: `<space>:<rest>` where\n // `<rest>` is the existing dot-qualified or bare form (`<ns>.<Name>` or `<Name>`).\n // Multiple colons (e.g. `a:b:c`) are invalid.\n const colonCount = (baseTypeSource.match(/:/g) ?? []).length;\n if (colonCount > 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n\n let typeRefSource: string;\n if (colonCount === 1) {\n // Colon-prefix form: `<space>:<rest>`\n const colonIndex = baseTypeSource.indexOf(':');\n const spaceCandidate = baseTypeSource.slice(0, colonIndex);\n typeRefSource = baseTypeSource.slice(colonIndex + 1);\n // Validate space identifier\n if (!/^[A-Za-z_]\\w*$/.test(spaceCandidate)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n typeContractSpaceId = spaceCandidate;\n } else {\n typeRefSource = baseTypeSource;\n }\n\n const dotCount = (typeRefSource.match(/\\./g) ?? []).length;\n if (dotCount > 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_QUALIFIED_TYPE',\n message: `Nested dot-qualified type \"${baseTypeSource}\" is not supported; use exactly one qualifier segment (e.g. \"ns.TypeName\")`,\n span: createInlineSpan(\n context,\n lineIndex,\n typeStartColumn,\n typeStartColumn + baseTypeSource.length,\n ),\n });\n return undefined;\n }\n const singleMatch = typeRefSource.match(/^([A-Za-z_]\\w*)(?:\\.([A-Za-z_]\\w*))?$/);\n if (!singleMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n if (singleMatch[2] !== undefined) {\n typeNamespaceId = singleMatch[1];\n typeName = singleMatch[2];\n } else {\n typeName = singleMatch[1] ?? '';\n }\n }\n\n const attributes: PslFieldAttribute[] = [];\n const attributeSource = attributePart.trimStart();\n const leadingAttributeWhitespace = attributePart.length - attributeSource.length;\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n attributeSource,\n trimmedStartColumn +\n fieldName.length +\n separator.length +\n typeAndAttributeSplit.attributeOffset +\n leadingAttributeWhitespace,\n );\n if (!tokenParse.ok) {\n return {\n kind: 'field',\n name: fieldName,\n typeName,\n ...ifDefined('typeNamespaceId', typeNamespaceId),\n ...ifDefined('typeContractSpaceId', typeContractSpaceId),\n ...ifDefined('typeConstructor', typeConstructor),\n optional,\n list,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n }\n\n for (const token of tokenParse.tokens) {\n const parsed = parseAttributeToken(context, {\n token: token.text,\n target: 'field',\n lineIndex,\n span: token.span,\n });\n if (parsed) {\n attributes.push(parsed);\n }\n }\n\n return {\n kind: 'field',\n name: fieldName,\n typeName,\n ...ifDefined('typeNamespaceId', typeNamespaceId),\n ...ifDefined('typeContractSpaceId', typeContractSpaceId),\n ...ifDefined('typeConstructor', typeConstructor),\n optional,\n list,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n}\n\nfunction isQuoteEscaped(value: string, quoteIndex: number): boolean {\n let backslashCount = 0;\n\n for (let index = quoteIndex - 1; index >= 0 && value[index] === '\\\\'; index -= 1) {\n backslashCount += 1;\n }\n\n return backslashCount % 2 === 1;\n}\n\nfunction splitTypeAndAttributes(value: string): {\n readonly typeSource: string;\n readonly attributeSource: string;\n readonly attributeOffset: number;\n} {\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n let quote: '\"' | \"'\" | null = null;\n\n for (let index = 0; index < value.length; index += 1) {\n const character = value[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === '(') {\n depthParen += 1;\n continue;\n }\n if (character === ')') {\n depthParen = Math.max(0, depthParen - 1);\n continue;\n }\n if (character === '[') {\n depthBracket += 1;\n continue;\n }\n if (character === ']') {\n depthBracket = Math.max(0, depthBracket - 1);\n continue;\n }\n if (character === '{') {\n depthBrace += 1;\n continue;\n }\n if (character === '}') {\n depthBrace = Math.max(0, depthBrace - 1);\n continue;\n }\n\n if (character === '@' && depthParen === 0 && depthBracket === 0 && depthBrace === 0) {\n return {\n typeSource: value.slice(0, index).trimEnd(),\n attributeSource: value.slice(index),\n attributeOffset: index,\n };\n }\n }\n\n return {\n typeSource: value.trimEnd(),\n attributeSource: '',\n attributeOffset: value.length,\n };\n}\n\nfunction parseAttributeToken(\n context: ParserContext,\n input: {\n readonly token: string;\n readonly target: PslAttributeTarget;\n readonly lineIndex: number;\n readonly span: PslSpan;\n },\n): PslAttribute | undefined {\n const expectsBlockPrefix = input.target === 'model' || input.target === 'enum';\n const targetLabel = input.target === 'enum' ? 'Enum' : 'Model';\n if (expectsBlockPrefix && !input.token.startsWith('@@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `${targetLabel} attribute \"${input.token}\" must use @@ prefix`,\n span: input.span,\n });\n return undefined;\n }\n if (!expectsBlockPrefix && !input.token.startsWith('@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Attribute \"${input.token}\" must use @ prefix`,\n span: input.span,\n });\n return undefined;\n }\n if (!expectsBlockPrefix && input.token.startsWith('@@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Attribute \"${input.token}\" is not valid in ${input.target} context`,\n span: input.span,\n });\n return undefined;\n }\n\n const rawBody = expectsBlockPrefix ? input.token.slice(2) : input.token.slice(1);\n const openParen = rawBody.indexOf('(');\n const closeParen = rawBody.lastIndexOf(')');\n const hasArgs = openParen >= 0 || closeParen >= 0;\n if ((openParen >= 0 && closeParen === -1) || (openParen === -1 && closeParen >= 0)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n\n const name = (openParen >= 0 ? rawBody.slice(0, openParen) : rawBody).trim();\n if (!/^[A-Za-z_][A-Za-z0-9_-]*(\\.[A-Za-z_][A-Za-z0-9_-]*)*$/.test(name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute name \"${name || input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n\n let args: readonly PslAttributeArgument[] = [];\n if (hasArgs && openParen >= 0 && closeParen >= openParen) {\n if (closeParen !== rawBody.length - 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid trailing syntax in attribute \"${input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n const argsRaw = rawBody.slice(openParen + 1, closeParen);\n const parsedArgs = parseArgumentList(context, {\n argsRaw,\n argsOffset: input.span.start.column - 1 + (expectsBlockPrefix ? 2 : 1) + openParen + 1,\n lineIndex: input.lineIndex,\n token: input.token,\n span: input.span,\n invalidCode: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n invalidEmptyArgumentMessage: `Invalid empty argument in attribute \"${input.token}\"`,\n invalidNamedArgumentMessage: (part) => `Invalid named argument syntax \"${part}\"`,\n });\n if (!parsedArgs) {\n return undefined;\n }\n args = parsedArgs;\n }\n\n return {\n kind: 'attribute',\n target: input.target,\n name,\n args,\n span: input.span,\n };\n}\n\nfunction parseArgumentList(\n context: ParserContext,\n input: {\n readonly argsRaw: string;\n readonly argsOffset: number;\n readonly lineIndex: number;\n readonly token: string;\n readonly span: PslSpan;\n readonly invalidCode: PslDiagnosticCode;\n readonly invalidEmptyArgumentMessage: string;\n readonly invalidNamedArgumentMessage: (part: string) => string;\n },\n): readonly PslAttributeArgument[] | undefined {\n const trimmed = input.argsRaw.trim();\n if (trimmed.length === 0) {\n return [];\n }\n\n const parts = splitTopLevelSegments(input.argsRaw, ',');\n const args: PslAttributeArgument[] = [];\n\n for (const part of parts) {\n const original = part.value;\n const trimmedPart = original.trim();\n if (trimmedPart.length === 0) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidEmptyArgumentMessage,\n span: input.span,\n });\n return undefined;\n }\n\n const leadingWhitespace = original.length - original.trimStart().length;\n const partStart = input.argsOffset + part.start + leadingWhitespace;\n const partEnd = partStart + trimmedPart.length;\n const partSpan = createInlineSpan(context, input.lineIndex, partStart, partEnd);\n\n const namedSplit = splitTopLevelSegments(trimmedPart, ':');\n if (namedSplit.length > 1) {\n const first = namedSplit[0];\n if (!first) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidNamedArgumentMessage(trimmedPart),\n span: partSpan,\n });\n return undefined;\n }\n const name = first.value.trim();\n const rawValue = trimmedPart.slice(first.end + 1).trim();\n if (!name || rawValue.length === 0) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidNamedArgumentMessage(trimmedPart),\n span: partSpan,\n });\n return undefined;\n }\n args.push({\n kind: 'named',\n name,\n value: normalizeAttributeArgumentValue(rawValue),\n span: partSpan,\n });\n continue;\n }\n\n args.push({\n kind: 'positional',\n value: normalizeAttributeArgumentValue(trimmedPart),\n span: partSpan,\n });\n }\n\n return args;\n}\n\nfunction normalizeAttributeArgumentValue(value: string): string {\n return value.trim();\n}\n\nfunction findBlockBounds(context: ParserContext, startLine: number): BlockBounds {\n let depth = 0;\n\n for (let lineIndex = startLine; lineIndex < context.lines.length; lineIndex += 1) {\n const line = stripInlineComment(context.lines[lineIndex] ?? '');\n let quote: '\"' | \"'\" | null = null;\n for (let index = 0; index < line.length; index += 1) {\n const character = line[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(line, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n\n if (character === '{') {\n depth += 1;\n }\n if (character === '}') {\n depth -= 1;\n if (depth === 0) {\n return { startLine, endLine: lineIndex, closed: true };\n }\n }\n }\n }\n\n pushDiagnostic(context, {\n code: 'PSL_UNTERMINATED_BLOCK',\n message: 'Unterminated block declaration',\n span: createTrimmedLineSpan(context, startLine),\n });\n return {\n startLine,\n endLine: context.lines.length - 1,\n closed: false,\n };\n}\n\ninterface TopLevelSegment {\n readonly value: string;\n readonly start: number;\n readonly end: number;\n}\n\nfunction splitTopLevelSegments(value: string, separator: ',' | ':'): TopLevelSegment[] {\n const parts: TopLevelSegment[] = [];\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n let quote: '\"' | \"'\" | null = null;\n let start = 0;\n\n for (let index = 0; index < value.length; index += 1) {\n const character = value[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n\n if (character === '(') {\n depthParen += 1;\n continue;\n }\n if (character === ')') {\n depthParen = Math.max(0, depthParen - 1);\n continue;\n }\n if (character === '[') {\n depthBracket += 1;\n continue;\n }\n if (character === ']') {\n depthBracket = Math.max(0, depthBracket - 1);\n continue;\n }\n if (character === '{') {\n depthBrace += 1;\n continue;\n }\n if (character === '}') {\n depthBrace = Math.max(0, depthBrace - 1);\n continue;\n }\n\n if (character === separator && depthParen === 0 && depthBracket === 0 && depthBrace === 0) {\n parts.push({\n value: value.slice(start, index),\n start,\n end: index,\n });\n start = index + 1;\n }\n }\n\n parts.push({\n value: value.slice(start),\n start,\n end: value.length,\n });\n return parts;\n}\n\nfunction extractAttributeTokensWithSpans(\n context: ParserContext,\n lineIndex: number,\n value: string,\n startColumn: number,\n): { readonly ok: boolean; readonly tokens: readonly { text: string; span: PslSpan }[] } {\n const tokens: { text: string; span: PslSpan }[] = [];\n let index = 0;\n while (index < value.length) {\n while (index < value.length && /\\s/.test(value[index] ?? '')) {\n index += 1;\n }\n if (index >= value.length) {\n break;\n }\n\n if (value[index] !== '@') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + index, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n const start = index;\n index += 1;\n if (value[index] === '@') {\n index += 1;\n }\n\n const nameStart = index;\n while (index < value.length && /[A-Za-z0-9_.-]/.test(value[index] ?? '')) {\n index += 1;\n }\n\n if (index === nameStart) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.slice(start).trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + start, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n if (value[index] === '(') {\n let depth = 0;\n let quote: '\"' | \"'\" | null = null;\n while (index < value.length) {\n const char = value[index] ?? '';\n if (quote) {\n if (char === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n\n if (char === '(') {\n depth += 1;\n } else if (char === ')') {\n depth -= 1;\n if (depth === 0) {\n index += 1;\n break;\n }\n }\n index += 1;\n }\n if (depth !== 0) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Unterminated attribute argument list in \"${value.slice(start).trim()}\"`,\n span: createInlineSpan(\n context,\n lineIndex,\n startColumn + start,\n startColumn + value.length,\n ),\n });\n return { ok: false, tokens };\n }\n }\n\n const tokenText = value.slice(start, index).trim();\n tokens.push({\n text: tokenText,\n span: createInlineSpan(context, lineIndex, startColumn + start, startColumn + index),\n });\n\n while (index < value.length && /\\s/.test(value[index] ?? '')) {\n index += 1;\n }\n\n if (index < value.length && value[index] !== '@') {\n break;\n }\n }\n\n if (index < value.length && value[index] !== '@') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + index, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n return { ok: true, tokens };\n}\n\nfunction stripInlineComment(line: string): string {\n let quote: '\"' | \"'\" | null = null;\n for (let index = 0; index < line.length - 1; index += 1) {\n const current = line[index] ?? '';\n const next = line[index + 1] ?? '';\n\n if (quote) {\n if (current === quote && !isQuoteEscaped(line, index)) {\n quote = null;\n }\n continue;\n }\n\n if (current === '\"' || current === \"'\") {\n quote = current;\n continue;\n }\n\n if (current === '/' && next === '/') {\n return line.slice(0, index);\n }\n }\n\n return line;\n}\n\nfunction computeLineOffsets(schema: string): number[] {\n const offsets = [0];\n for (let index = 0; index < schema.length; index += 1) {\n if (schema[index] === '\\n') {\n offsets.push(index + 1);\n }\n }\n return offsets;\n}\n\nfunction firstNonWhitespaceColumn(line: string): number {\n const first = line.search(/\\S/);\n return first === -1 ? 0 : first;\n}\n\nfunction createInlineSpan(\n context: ParserContext,\n lineIndex: number,\n startColumn: number,\n endColumn: number,\n): PslSpan {\n return {\n start: createPosition(context, lineIndex, startColumn),\n end: createPosition(context, lineIndex, endColumn),\n };\n}\n\nfunction createTrimmedLineSpan(context: ParserContext, lineIndex: number): PslSpan {\n const line = context.lines[lineIndex] ?? '';\n const startColumn = firstNonWhitespaceColumn(line);\n return {\n start: createPosition(context, lineIndex, startColumn),\n end: createPosition(context, lineIndex, line.length),\n };\n}\n\nfunction createLineRangeSpan(context: ParserContext, startLine: number, endLine: number): PslSpan {\n const startLineText = context.lines[startLine] ?? '';\n const endLineText = context.lines[endLine] ?? '';\n const startColumn = firstNonWhitespaceColumn(startLineText);\n return {\n start: createPosition(context, startLine, startColumn),\n end: createPosition(context, endLine, endLineText.length),\n };\n}\n\nfunction createPosition(\n context: ParserContext,\n lineIndex: number,\n columnIndex: number,\n): PslPosition {\n const clampedLineIndex = Math.max(0, Math.min(lineIndex, context.lineOffsets.length - 1));\n const lineText = context.lines[clampedLineIndex] ?? '';\n const clampedColumnIndex = Math.max(0, Math.min(columnIndex, lineText.length));\n return {\n offset: (context.lineOffsets[clampedLineIndex] ?? 0) + clampedColumnIndex,\n line: clampedLineIndex + 1,\n column: clampedColumnIndex + 1,\n };\n}\n\nfunction pushDiagnostic(\n context: ParserContext,\n diagnostic: Omit<PslDiagnostic, 'sourceId'> & { readonly code: PslDiagnosticCode },\n): void {\n context.diagnostics.push({\n ...diagnostic,\n sourceId: context.sourceId,\n });\n}\n\nfunction lookupExtensionBlockDescriptor(\n namespace: AuthoringPslBlockDescriptorNamespace,\n keyword: string,\n): AuthoringPslBlockDescriptor | undefined {\n if (!Object.hasOwn(namespace, keyword)) {\n return undefined;\n }\n const value = namespace[keyword];\n return isAuthoringPslBlockDescriptor(value) ? value : undefined;\n}\n\n/**\n * Reads an extension block body generically, driven by the descriptor's\n * `parameters` map. Each body line is one of:\n *\n * - `@@name(args…)` — a block attribute, captured in `blockAttributes`\n * - `key = <rhs>` — a parameter entry, captured in `parameters` per descriptor\n * - `key` — a bare-identifier entry (no `= value`), captured as `kind:'bare'`\n *\n * Duplicate parameter keys emit `PSL_EXTENSION_DUPLICATE_PARAMETER`; the first\n * occurrence wins. `@@` attribute lines are not validated here (name or args);\n * that is a concern of the consuming interpreter.\n */\nfunction parseExtensionBlock(\n context: ParserContext,\n descriptor: AuthoringPslBlockDescriptor,\n blockName: string,\n keywordLineIndex: number,\n bounds: BlockBounds,\n): PslExtensionBlock {\n const parameters: Record<string, PslExtensionBlockParamValue> = {};\n const blockAttributes: PslExtensionBlockAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attr = parseExtensionBlockAttribute(context, line, lineIndex);\n if (attr !== undefined) {\n blockAttributes.push(attr);\n }\n continue;\n }\n\n const assignMatch = line.match(/^([A-Za-z_]\\w*)\\s*=\\s*(.+)$/);\n if (assignMatch) {\n const key = assignMatch[1] ?? '';\n const rhsRaw = (assignMatch[2] ?? '').trim();\n\n if (Object.hasOwn(parameters, key)) {\n pushDiagnostic(context, {\n code: 'PSL_EXTENSION_DUPLICATE_PARAMETER',\n message: `Duplicate parameter \"${key}\" in \"${descriptor.keyword}\" block \"${blockName}\"; first occurrence wins`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const paramDescriptor = descriptor.parameters[key];\n if (paramDescriptor === undefined) {\n parameters[key] = {\n kind: 'value',\n raw: rhsRaw,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n } else {\n const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);\n if (captured !== undefined) {\n parameters[key] = captured;\n }\n }\n continue;\n }\n\n const bareMatch = line.match(/^([A-Za-z_]\\w*)$/);\n if (bareMatch) {\n const key = bareMatch[1] ?? '';\n\n if (!descriptor.variadicParameters) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Invalid extension block body line \"${line}\"; expected \"key = value\" or \"@@attribute\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n if (Object.hasOwn(descriptor.parameters, key)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Parameter \"${key}\" in \"${descriptor.keyword}\" block \"${blockName}\" is declared in the descriptor and must be supplied as \"${key} = value\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n if (Object.hasOwn(parameters, key)) {\n pushDiagnostic(context, {\n code: 'PSL_EXTENSION_DUPLICATE_PARAMETER',\n message: `Duplicate parameter \"${key}\" in \"${descriptor.keyword}\" block \"${blockName}\"; first occurrence wins`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n parameters[key] = { kind: 'bare', span: createTrimmedLineSpan(context, lineIndex) };\n continue;\n }\n\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Invalid extension block body line \"${line}\"; expected \"key = value\", \"key\", or \"@@attribute\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n }\n\n return {\n kind: descriptor.discriminator,\n name: blockName,\n parameters,\n blockAttributes,\n span: createLineRangeSpan(context, keywordLineIndex, bounds.endLine),\n };\n}\n\n/**\n * Parses a `@@name(args…)` block-attribute line inside an extension block\n * using the shared block-attribute tokeniser (`extractAttributeTokensWithSpans`\n * + `parseAttributeToken`). Returns undefined (and emits a diagnostic) on\n * malformed syntax.\n */\nfunction parseExtensionBlockAttribute(\n context: ParserContext,\n line: string,\n lineIndex: number,\n): PslExtensionBlockAttribute | undefined {\n const rawLine = context.lines[lineIndex] ?? '';\n const startCol = firstNonWhitespaceColumn(rawLine);\n\n const tokenParse = extractAttributeTokensWithSpans(context, lineIndex, line, startCol);\n if (!tokenParse.ok || tokenParse.tokens.length !== 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE',\n message: `Invalid extension block attribute \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n const token = tokenParse.tokens[0];\n if (!token) {\n return undefined;\n }\n const parsed = parseAttributeToken(context, {\n token: token.text,\n target: 'model',\n lineIndex,\n span: token.span,\n });\n if (!parsed) {\n return undefined;\n }\n const args: PslExtensionBlockAttributeArg[] = parsed.args\n .filter((a): a is PslAttributeArgument & { kind: 'positional' } => a.kind === 'positional')\n .map((a) => ({ kind: 'positional' as const, value: a.value, span: a.span }));\n return { name: parsed.name, args, span: parsed.span };\n}\n\n/**\n * Captures a single parameter RHS string according to the declared parameter\n * kind. Returns `undefined` and pushes a diagnostic only if the syntax is\n * genuinely malformed (e.g. a `list` with no opening bracket). Value\n * acceptance (codec, option-in-set, ref resolution) is handled by the validator.\n */\nfunction captureParamRhs(\n context: ParserContext,\n lineIndex: number,\n rhs: string,\n param: AuthoringPslBlockDescriptor['parameters'][string],\n): PslExtensionBlockParamValue | undefined {\n const span = createTrimmedLineSpan(context, lineIndex);\n\n switch (param.kind) {\n case 'ref': {\n return { kind: 'ref', identifier: rhs, span };\n }\n case 'value': {\n return { kind: 'value', raw: rhs, span };\n }\n case 'option': {\n return { kind: 'option', token: rhs, span };\n }\n case 'list': {\n if (!rhs.startsWith('[') || !rhs.endsWith(']')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Expected a bracketed list \"[…]\" for list parameter, got \"${rhs}\"`,\n span,\n });\n return undefined;\n }\n const inner = rhs.slice(1, -1).trim();\n const items: PslExtensionBlockParamValue[] = [];\n if (inner.length > 0) {\n const segments = splitTopLevelSegments(inner, ',');\n for (const segment of segments) {\n const itemRhs = segment.value.trim();\n if (itemRhs.length === 0) {\n continue;\n }\n const item = captureParamRhs(context, lineIndex, itemRhs, param.of);\n if (item !== undefined) {\n items.push(item);\n }\n }\n }\n return { kind: 'list', items, span };\n }\n }\n}\n"],"mappings":"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"}
package/dist/parser.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as parsePslDocument } from "./parser-Cw_zV0M5.mjs";
1
+ import { t as parsePslDocument } from "./parser-Dw33hDIx.mjs";
2
2
  export { parsePslDocument };
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@prisma-next/psl-parser",
3
- "version": "0.13.0-dev.2",
3
+ "version": "0.13.0-dev.21",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Reusable parser for Prisma Schema Language (PSL)",
8
8
  "dependencies": {
9
- "@prisma-next/framework-components": "0.13.0-dev.2",
10
- "@prisma-next/utils": "0.13.0-dev.2"
9
+ "@prisma-next/framework-components": "0.13.0-dev.21",
10
+ "@prisma-next/utils": "0.13.0-dev.21"
11
11
  },
12
12
  "devDependencies": {
13
- "@prisma-next/tsconfig": "0.13.0-dev.2",
14
- "@prisma-next/tsdown": "0.13.0-dev.2",
13
+ "@prisma-next/tsconfig": "0.13.0-dev.21",
14
+ "@prisma-next/tsdown": "0.13.0-dev.21",
15
15
  "tsdown": "0.22.1",
16
16
  "typescript": "5.9.3",
17
17
  "vitest": "4.1.8"
@@ -15,6 +15,15 @@ export type {
15
15
  PslDocumentAst,
16
16
  PslEnum,
17
17
  PslEnumValue,
18
+ PslExtensionBlock,
19
+ PslExtensionBlockAttribute,
20
+ PslExtensionBlockAttributeArg,
21
+ PslExtensionBlockParamBare,
22
+ PslExtensionBlockParamList,
23
+ PslExtensionBlockParamOption,
24
+ PslExtensionBlockParamRef,
25
+ PslExtensionBlockParamScalarValue,
26
+ PslExtensionBlockParamValue,
18
27
  PslField,
19
28
  PslFieldAttribute,
20
29
  PslModel,
@@ -26,5 +35,10 @@ export type {
26
35
  PslTypeConstructorCall,
27
36
  PslTypesBlock,
28
37
  } from '@prisma-next/framework-components/psl-ast';
38
+ export {
39
+ flatPslEnums,
40
+ flatPslModels,
41
+ namespacePslExtensionBlocks,
42
+ } from '@prisma-next/framework-components/psl-ast';
29
43
  export { getPositionalArgument, parseQuotedStringLiteral } from '../attribute-helpers';
30
44
  export { parsePslDocument } from '../parser';
package/src/parser.ts CHANGED
@@ -17,6 +17,8 @@ import type {
17
17
  PslEnum,
18
18
  PslEnumValue,
19
19
  PslExtensionBlock,
20
+ PslExtensionBlockAttribute,
21
+ PslExtensionBlockAttributeArg,
20
22
  PslExtensionBlockParamValue,
21
23
  PslField,
22
24
  PslFieldAttribute,
@@ -1592,18 +1594,15 @@ function lookupExtensionBlockDescriptor(
1592
1594
 
1593
1595
  /**
1594
1596
  * Reads an extension block body generically, driven by the descriptor's
1595
- * `parameters` map. Each `key = <rhs>` line in the body is matched against
1596
- * a declared parameter and the RHS is captured per the parameter's kind:
1597
+ * `parameters` map. Each body line is one of:
1597
1598
  *
1598
- * - `ref` → the bareword identifier token (`PslExtensionBlockParamRef`)
1599
- * - `value` → the raw RHS text verbatim (`PslExtensionBlockParamScalarValue`)
1600
- * - `option` the chosen bareword token (`PslExtensionBlockParamOption`)
1601
- * - `list` → bracketed `[a, b, …]` list, each element captured per `of`
1602
- * (`PslExtensionBlockParamList`)
1599
+ * - `@@name(args…)` a block attribute, captured in `blockAttributes`
1600
+ * - `key = <rhs>` a parameter entry, captured in `parameters` per descriptor
1601
+ * - `key` a bare-identifier entry (no `= value`), captured as `kind:'bare'`
1603
1602
  *
1604
- * No validation runs here (unknown key, missing required, codec acceptance,
1605
- * option-in-set, ref resolution). A body line that is not `key = value`
1606
- * shaped emits a `PSL_INVALID_EXTENSION_BLOCK_MEMBER` parse diagnostic.
1603
+ * Duplicate parameter keys emit `PSL_EXTENSION_DUPLICATE_PARAMETER`; the first
1604
+ * occurrence wins. `@@` attribute lines are not validated here (name or args);
1605
+ * that is a concern of the consuming interpreter.
1607
1606
  */
1608
1607
  function parseExtensionBlock(
1609
1608
  context: ParserContext,
@@ -1613,6 +1612,7 @@ function parseExtensionBlock(
1613
1612
  bounds: BlockBounds,
1614
1613
  ): PslExtensionBlock {
1615
1614
  const parameters: Record<string, PslExtensionBlockParamValue> = {};
1615
+ const blockAttributes: PslExtensionBlockAttribute[] = [];
1616
1616
 
1617
1617
  for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {
1618
1618
  const raw = context.lines[lineIndex] ?? '';
@@ -1621,44 +1621,137 @@ function parseExtensionBlock(
1621
1621
  continue;
1622
1622
  }
1623
1623
 
1624
- const assignMatch = line.match(/^([A-Za-z_]\w*)\s*=\s*(.+)$/);
1625
- if (!assignMatch) {
1626
- pushDiagnostic(context, {
1627
- code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
1628
- message: `Invalid extension block body line "${line}"; expected "key = value"`,
1629
- span: createTrimmedLineSpan(context, lineIndex),
1630
- });
1624
+ if (line.startsWith('@@')) {
1625
+ const attr = parseExtensionBlockAttribute(context, line, lineIndex);
1626
+ if (attr !== undefined) {
1627
+ blockAttributes.push(attr);
1628
+ }
1631
1629
  continue;
1632
1630
  }
1633
1631
 
1634
- const key = assignMatch[1] ?? '';
1635
- const rhsRaw = (assignMatch[2] ?? '').trim();
1636
- const paramDescriptor = descriptor.parameters[key];
1632
+ const assignMatch = line.match(/^([A-Za-z_]\w*)\s*=\s*(.+)$/);
1633
+ if (assignMatch) {
1634
+ const key = assignMatch[1] ?? '';
1635
+ const rhsRaw = (assignMatch[2] ?? '').trim();
1637
1636
 
1638
- if (paramDescriptor === undefined) {
1639
- // Unknown parameter — captured as a raw value; the generic validator reports this.
1640
- parameters[key] = {
1641
- kind: 'value',
1642
- raw: rhsRaw,
1643
- span: createTrimmedLineSpan(context, lineIndex),
1644
- };
1637
+ if (Object.hasOwn(parameters, key)) {
1638
+ pushDiagnostic(context, {
1639
+ code: 'PSL_EXTENSION_DUPLICATE_PARAMETER',
1640
+ message: `Duplicate parameter "${key}" in "${descriptor.keyword}" block "${blockName}"; first occurrence wins`,
1641
+ span: createTrimmedLineSpan(context, lineIndex),
1642
+ });
1643
+ continue;
1644
+ }
1645
+
1646
+ const paramDescriptor = descriptor.parameters[key];
1647
+ if (paramDescriptor === undefined) {
1648
+ parameters[key] = {
1649
+ kind: 'value',
1650
+ raw: rhsRaw,
1651
+ span: createTrimmedLineSpan(context, lineIndex),
1652
+ };
1653
+ } else {
1654
+ const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);
1655
+ if (captured !== undefined) {
1656
+ parameters[key] = captured;
1657
+ }
1658
+ }
1645
1659
  continue;
1646
1660
  }
1647
1661
 
1648
- const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);
1649
- if (captured !== undefined) {
1650
- parameters[key] = captured;
1662
+ const bareMatch = line.match(/^([A-Za-z_]\w*)$/);
1663
+ if (bareMatch) {
1664
+ const key = bareMatch[1] ?? '';
1665
+
1666
+ if (!descriptor.variadicParameters) {
1667
+ pushDiagnostic(context, {
1668
+ code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
1669
+ message: `Invalid extension block body line "${line}"; expected "key = value" or "@@attribute"`,
1670
+ span: createTrimmedLineSpan(context, lineIndex),
1671
+ });
1672
+ continue;
1673
+ }
1674
+
1675
+ if (Object.hasOwn(descriptor.parameters, key)) {
1676
+ pushDiagnostic(context, {
1677
+ code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
1678
+ message: `Parameter "${key}" in "${descriptor.keyword}" block "${blockName}" is declared in the descriptor and must be supplied as "${key} = value"`,
1679
+ span: createTrimmedLineSpan(context, lineIndex),
1680
+ });
1681
+ continue;
1682
+ }
1683
+
1684
+ if (Object.hasOwn(parameters, key)) {
1685
+ pushDiagnostic(context, {
1686
+ code: 'PSL_EXTENSION_DUPLICATE_PARAMETER',
1687
+ message: `Duplicate parameter "${key}" in "${descriptor.keyword}" block "${blockName}"; first occurrence wins`,
1688
+ span: createTrimmedLineSpan(context, lineIndex),
1689
+ });
1690
+ continue;
1691
+ }
1692
+
1693
+ parameters[key] = { kind: 'bare', span: createTrimmedLineSpan(context, lineIndex) };
1694
+ continue;
1651
1695
  }
1696
+
1697
+ pushDiagnostic(context, {
1698
+ code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
1699
+ message: `Invalid extension block body line "${line}"; expected "key = value", "key", or "@@attribute"`,
1700
+ span: createTrimmedLineSpan(context, lineIndex),
1701
+ });
1652
1702
  }
1653
1703
 
1654
1704
  return {
1655
1705
  kind: descriptor.discriminator,
1656
1706
  name: blockName,
1657
1707
  parameters,
1708
+ blockAttributes,
1658
1709
  span: createLineRangeSpan(context, keywordLineIndex, bounds.endLine),
1659
1710
  };
1660
1711
  }
1661
1712
 
1713
+ /**
1714
+ * Parses a `@@name(args…)` block-attribute line inside an extension block
1715
+ * using the shared block-attribute tokeniser (`extractAttributeTokensWithSpans`
1716
+ * + `parseAttributeToken`). Returns undefined (and emits a diagnostic) on
1717
+ * malformed syntax.
1718
+ */
1719
+ function parseExtensionBlockAttribute(
1720
+ context: ParserContext,
1721
+ line: string,
1722
+ lineIndex: number,
1723
+ ): PslExtensionBlockAttribute | undefined {
1724
+ const rawLine = context.lines[lineIndex] ?? '';
1725
+ const startCol = firstNonWhitespaceColumn(rawLine);
1726
+
1727
+ const tokenParse = extractAttributeTokensWithSpans(context, lineIndex, line, startCol);
1728
+ if (!tokenParse.ok || tokenParse.tokens.length !== 1) {
1729
+ pushDiagnostic(context, {
1730
+ code: 'PSL_INVALID_EXTENSION_BLOCK_ATTRIBUTE',
1731
+ message: `Invalid extension block attribute "${line}"`,
1732
+ span: createTrimmedLineSpan(context, lineIndex),
1733
+ });
1734
+ return undefined;
1735
+ }
1736
+ const token = tokenParse.tokens[0];
1737
+ if (!token) {
1738
+ return undefined;
1739
+ }
1740
+ const parsed = parseAttributeToken(context, {
1741
+ token: token.text,
1742
+ target: 'model',
1743
+ lineIndex,
1744
+ span: token.span,
1745
+ });
1746
+ if (!parsed) {
1747
+ return undefined;
1748
+ }
1749
+ const args: PslExtensionBlockAttributeArg[] = parsed.args
1750
+ .filter((a): a is PslAttributeArgument & { kind: 'positional' } => a.kind === 'positional')
1751
+ .map((a) => ({ kind: 'positional' as const, value: a.value, span: a.span }));
1752
+ return { name: parsed.name, args, span: parsed.span };
1753
+ }
1754
+
1662
1755
  /**
1663
1756
  * Captures a single parameter RHS string according to the declared parameter
1664
1757
  * kind. Returns `undefined` and pushes a diagnostic only if the syntax is
@@ -1 +0,0 @@
1
- {"version":3,"file":"parser-Cw_zV0M5.mjs","names":[],"sources":["../src/parser.ts"],"sourcesContent":["import type {\n AuthoringPslBlockDescriptor,\n AuthoringPslBlockDescriptorNamespace,\n} from '@prisma-next/framework-components/authoring';\nimport { isAuthoringPslBlockDescriptor } from '@prisma-next/framework-components/authoring';\nimport { emptyCodecLookup } from '@prisma-next/framework-components/codec';\nimport type {\n ParsePslDocumentInput,\n ParsePslDocumentResult,\n PslAttribute,\n PslAttributeArgument,\n PslAttributeTarget,\n PslCompositeType,\n PslDiagnostic,\n PslDiagnosticCode,\n PslDocumentAst,\n PslEnum,\n PslEnumValue,\n PslExtensionBlock,\n PslExtensionBlockParamValue,\n PslField,\n PslFieldAttribute,\n PslModel,\n PslModelAttribute,\n PslNamedTypeDeclaration,\n PslNamespace,\n PslPosition,\n PslSpan,\n PslTypeConstructorCall,\n PslTypesBlock,\n} from '@prisma-next/framework-components/psl-ast';\nimport {\n makePslNamespace,\n makePslNamespaceEntries,\n namespacePslExtensionBlocks,\n UNSPECIFIED_PSL_NAMESPACE_ID,\n validateExtensionBlock,\n} from '@prisma-next/framework-components/psl-ast';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\nconst SCALAR_TYPES = new Set([\n 'String',\n 'Boolean',\n 'Int',\n 'BigInt',\n 'Float',\n 'Decimal',\n 'DateTime',\n 'Json',\n 'Bytes',\n]);\n\ninterface BlockBounds {\n readonly startLine: number;\n readonly endLine: number;\n readonly closed: boolean;\n}\n\ninterface ParserContext {\n readonly schema: string;\n readonly sourceId: string;\n readonly lines: readonly string[];\n readonly lineOffsets: readonly number[];\n readonly diagnostics: PslDiagnostic[];\n}\n\nexport function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocumentResult {\n const normalizedSchema = input.schema.replaceAll('\\r\\n', '\\n');\n const lines = normalizedSchema.split('\\n');\n const lineOffsets = computeLineOffsets(normalizedSchema);\n const diagnostics: PslDiagnostic[] = [];\n const context: ParserContext = {\n schema: normalizedSchema,\n sourceId: input.sourceId,\n lines,\n lineOffsets,\n diagnostics,\n };\n\n interface NamespaceAccumulator {\n name: string;\n models: PslModel[];\n enums: PslEnum[];\n compositeTypes: PslCompositeType[];\n extensionBlocks: PslExtensionBlock[];\n span: PslSpan | undefined;\n }\n\n const namespaceOrder: string[] = [];\n const namespacesByName = new Map<string, NamespaceAccumulator>();\n const getOrCreateNamespace = (\n name: string,\n spanIfNew: PslSpan | undefined,\n ): NamespaceAccumulator => {\n let acc = namespacesByName.get(name);\n if (!acc) {\n acc = {\n name,\n models: [],\n enums: [],\n compositeTypes: [],\n extensionBlocks: [],\n span: spanIfNew,\n };\n namespacesByName.set(name, acc);\n namespaceOrder.push(name);\n }\n return acc;\n };\n\n let typesBlock: PslTypesBlock | undefined;\n const pslBlockNamespace: AuthoringPslBlockDescriptorNamespace = input.pslBlockDescriptors ?? {};\n\n // Walk a contiguous range of lines, routing top-level declarations into the\n // active namespace bucket. Called once for the whole document and once per\n // `namespace { … }` block body; nested `namespace { … }` or `types { … }`\n // blocks inside a namespace body are rejected with a diagnostic.\n const parseBody = (\n startLine: number,\n endLineExclusive: number,\n currentNamespaceName: string,\n isInsideNamespace: boolean,\n ): void => {\n let lineIndex = startLine;\n while (lineIndex < endLineExclusive) {\n const rawLine = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(rawLine).trim();\n if (line.length === 0) {\n lineIndex += 1;\n continue;\n }\n\n const modelMatch = line.match(/^model\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (modelMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = modelMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.models.push(parseModelBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const enumMatch = line.match(/^enum\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (enumMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = enumMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.enums.push(parseEnumBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const compositeTypeMatch = line.match(/^type\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (compositeTypeMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = compositeTypeMatch[1] ?? '';\n if (name.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n acc.compositeTypes.push(parseCompositeTypeBlock(context, name, bounds));\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const namespaceMatch = line.match(/^namespace\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (namespaceMatch) {\n const bounds = findBlockBounds(context, lineIndex);\n const name = namespaceMatch[1] ?? '';\n if (isInsideNamespace) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message: `Recursive \"namespace ${name}\" block is not allowed; namespace blocks may not nest`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (name === UNSPECIFIED_PSL_NAMESPACE_ID) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message: `Namespace name \"${UNSPECIFIED_PSL_NAMESPACE_ID}\" is reserved for the parser-synthesised bucket for top-level declarations`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (name.length > 0) {\n getOrCreateNamespace(name, createTrimmedLineSpan(context, lineIndex));\n parseBody(bounds.startLine + 1, bounds.endLine, name, true);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n if (/^types\\s*\\{$/.test(line)) {\n const bounds = findBlockBounds(context, lineIndex);\n if (isInsideNamespace) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_NAMESPACE_BLOCK',\n message:\n '`types` blocks must be declared at the document top level, not inside a namespace block',\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else if (typesBlock !== undefined) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: 'Only one top-level `types` block is allowed per document',\n span: createTrimmedLineSpan(context, lineIndex),\n });\n } else {\n typesBlock = parseTypesBlock(context, bounds);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n const extensionBlockMatch = line.match(/^([A-Za-z_]\\w*)\\s+([A-Za-z_]\\w*)\\s*\\{$/);\n if (extensionBlockMatch) {\n const keyword = extensionBlockMatch[1] ?? '';\n const blockName = extensionBlockMatch[2] ?? '';\n const descriptor = lookupExtensionBlockDescriptor(pslBlockNamespace, keyword);\n if (descriptor) {\n const bounds = findBlockBounds(context, lineIndex);\n if (blockName.length > 0) {\n const acc = getOrCreateNamespace(\n currentNamespaceName,\n createTrimmedLineSpan(context, lineIndex),\n );\n const node = parseExtensionBlock(context, descriptor, blockName, lineIndex, bounds);\n acc.extensionBlocks.push(node);\n }\n lineIndex = bounds.endLine + 1;\n continue;\n }\n }\n\n if (line.includes('{')) {\n const blockName = line.split(/\\s+/)[0] ?? 'block';\n pushDiagnostic(context, {\n code: 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK',\n message: `Unsupported top-level block \"${blockName}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n const bounds = findBlockBounds(context, lineIndex);\n lineIndex = bounds.endLine + 1;\n continue;\n }\n\n pushDiagnostic(context, {\n code: 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK',\n message: `Unsupported top-level declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n lineIndex += 1;\n }\n };\n\n parseBody(0, lines.length, UNSPECIFIED_PSL_NAMESPACE_ID, false);\n\n // Named-type validation: types are document-scoped (one block, outside any\n // namespace), so collision checks compare named-type names against every\n // model/enum/composite-type in every namespace.\n const allModels: PslModel[] = [];\n const allEnums: PslEnum[] = [];\n const allCompositeTypes: PslCompositeType[] = [];\n for (const name of namespaceOrder) {\n const acc = namespacesByName.get(name);\n if (!acc) continue;\n allModels.push(...acc.models);\n allEnums.push(...acc.enums);\n allCompositeTypes.push(...acc.compositeTypes);\n }\n\n const namedTypeNames = new Set(\n (typesBlock?.declarations ?? []).map((declaration) => declaration.name),\n );\n const modelNames = new Set(allModels.map((model) => model.name));\n const enumNames = new Set(allEnums.map((enumBlock) => enumBlock.name));\n const compositeTypeNames = new Set(allCompositeTypes.map((ct) => ct.name));\n for (const declaration of typesBlock?.declarations ?? []) {\n if (SCALAR_TYPES.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with scalar type \"${declaration.name}\"`,\n span: declaration.span,\n });\n continue;\n }\n if (modelNames.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with model name \"${declaration.name}\"`,\n span: declaration.span,\n });\n continue;\n }\n if (enumNames.has(declaration.name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Named type \"${declaration.name}\" conflicts with enum name \"${declaration.name}\"`,\n span: declaration.span,\n });\n }\n }\n\n const documentSpan: PslSpan = {\n start: createPosition(context, 0, 0),\n end: createPosition(\n context,\n Math.max(lines.length - 1, 0),\n (lines[Math.max(lines.length - 1, 0)] ?? '').length,\n ),\n };\n\n const namespaces: PslNamespace[] = [];\n for (const name of namespaceOrder) {\n const acc = namespacesByName.get(name);\n if (!acc) continue;\n // Drop the synthesised __unspecified__ entry when it ended up empty (e.g.\n // every declaration in the document lived inside an explicit\n // `namespace { … }` block). Keeping a phantom bucket would force every\n // downstream consumer to special-case \"namespace with no members\".\n if (\n name === UNSPECIFIED_PSL_NAMESPACE_ID &&\n acc.models.length === 0 &&\n acc.enums.length === 0 &&\n acc.compositeTypes.length === 0 &&\n acc.extensionBlocks.length === 0\n ) {\n continue;\n }\n const normalizedModels = acc.models.map((model) => ({\n ...model,\n fields: model.fields.map((field) => {\n if (!namedTypeNames.has(field.typeName)) {\n return field;\n }\n const hasRelationAttribute = field.attributes.some(\n (attribute) => attribute.name === 'relation',\n );\n if (\n hasRelationAttribute ||\n modelNames.has(field.typeName) ||\n enumNames.has(field.typeName) ||\n compositeTypeNames.has(field.typeName) ||\n SCALAR_TYPES.has(field.typeName)\n ) {\n return field;\n }\n return {\n ...field,\n typeRef: field.typeName,\n };\n }),\n }));\n namespaces.push(\n makePslNamespace({\n kind: 'namespace',\n name,\n entries: makePslNamespaceEntries(\n normalizedModels,\n acc.enums,\n acc.compositeTypes,\n acc.extensionBlocks,\n ),\n span: acc.span ?? documentSpan,\n }),\n );\n }\n\n // Validate extension blocks with the generic validator after the full\n // AST is assembled. The validator needs all namespaces for ref resolution.\n // It runs whenever pslBlockDescriptors are registered — codecLookup falls\n // back to emptyCodecLookup when not provided, which rejects value-kind\n // parameters with unknown codecs. Callers with value parameters should\n // always supply a codecLookup.\n if (Object.keys(pslBlockNamespace).length > 0) {\n const codecLookup = input.codecLookup ?? emptyCodecLookup;\n // Build a discriminator → descriptor reverse map from the descriptor\n // namespace. The parser keyed by keyword; the validator resolves by\n // node.kind (= discriminator) so we need the reverse direction.\n const descriptorByDiscriminator = new Map<string, AuthoringPslBlockDescriptor>();\n for (const value of Object.values(pslBlockNamespace)) {\n if (isAuthoringPslBlockDescriptor(value)) {\n descriptorByDiscriminator.set(value.discriminator, value);\n }\n }\n for (const ns of namespaces) {\n // Collect extension blocks from entries using the canonical helper, then\n // filter to only those whose discriminator is registered in the namespace.\n for (const block of namespacePslExtensionBlocks(ns)) {\n const descriptor = descriptorByDiscriminator.get(block.kind);\n if (descriptor === undefined) {\n continue;\n }\n const blockDiagnostics = validateExtensionBlock(\n block,\n descriptor,\n input.sourceId,\n codecLookup,\n {\n ownerNamespace: ns,\n allNamespaces: namespaces,\n },\n );\n diagnostics.push(...blockDiagnostics);\n }\n }\n }\n\n const ast: PslDocumentAst = {\n kind: 'document',\n sourceId: input.sourceId,\n namespaces,\n ...ifDefined('types', typesBlock),\n span: documentSpan,\n };\n\n return {\n ast,\n diagnostics,\n ok: diagnostics.length === 0,\n };\n}\n\nfunction parseModelBlock(context: ParserContext, name: string, bounds: BlockBounds): PslModel {\n const fields: PslField[] = [];\n const attributes: PslModelAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseModelAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n const field = parseField(context, line, lineIndex);\n if (field) {\n fields.push(field);\n }\n }\n\n return {\n kind: 'model',\n name,\n fields,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseCompositeTypeBlock(\n context: ParserContext,\n name: string,\n bounds: BlockBounds,\n): PslCompositeType {\n const fields: PslField[] = [];\n const attributes: PslAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseModelAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n const field = parseField(context, line, lineIndex);\n if (field) {\n fields.push(field);\n }\n }\n\n return {\n kind: 'compositeType',\n name,\n fields,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseEnumBlock(context: ParserContext, name: string, bounds: BlockBounds): PslEnum {\n const values: PslEnumValue[] = [];\n const attributes: PslAttribute[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n if (line.startsWith('@@')) {\n const attribute = parseEnumAttribute(context, line, lineIndex);\n if (attribute) {\n attributes.push(attribute);\n }\n continue;\n }\n\n // An enum member line is the bare member identifier, optionally followed\n // by a `@map(\"storage-label\")` attribute. The map attribute lets the\n // printer round-trip enum values whose original storage label is not a\n // valid PSL identifier (e.g. PostgreSQL enum labels with hyphens).\n const valueMatch = line.match(/^([A-Za-z_]\\w*)(?:\\s+@map\\(\\s*\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\))?$/);\n if (!valueMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const mapName = valueMatch[2] !== undefined ? unescapePslString(valueMatch[2]) : undefined;\n\n values.push({\n kind: 'enumValue',\n name: valueMatch[1] ?? '',\n ...(mapName !== undefined ? { mapName } : {}),\n span: createTrimmedLineSpan(context, lineIndex),\n });\n }\n\n return {\n kind: 'enum',\n name,\n values,\n attributes,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\n/**\n * Decode PSL escape sequences (`\\\\`, `\\\"`, `\\'`, `\\n`, `\\r`) inside a\n * quoted-literal body. The argument is the body of the literal with the\n * surrounding quotes already stripped by the caller. Mirrors the inverse\n * helper in `@prisma-next/psl-printer`'s `escapePslString` so a string\n * round-trips parser → printer → parser unchanged.\n */\nfunction unescapePslString(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n if (ch !== 0x5c /* '\\\\' */ || i + 1 >= value.length) {\n result += value[i];\n continue;\n }\n const next = value[i + 1];\n if (next === '\\\\' || next === '\"' || next === \"'\") {\n result += next;\n } else if (next === 'n') {\n result += '\\n';\n } else if (next === 'r') {\n result += '\\r';\n } else {\n result += '\\\\';\n result += next;\n }\n i++;\n }\n return result;\n}\n\nfunction parseTypesBlock(context: ParserContext, bounds: BlockBounds): PslTypesBlock {\n const declarations: PslNamedTypeDeclaration[] = [];\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const lineWithoutComment = stripInlineComment(raw);\n const line = lineWithoutComment.trim();\n if (line.length === 0) {\n continue;\n }\n\n const declarationMatch = line.match(/^([A-Za-z_]\\w*)\\s*=\\s*(.+)$/);\n if (!declarationMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Invalid types declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const declarationName = declarationMatch[1] ?? '';\n const trimmedStartColumn = firstNonWhitespaceColumn(raw);\n const declarationValue = (declarationMatch[2] ?? '').trim();\n const valueOffset = line.indexOf(declarationValue);\n const declarationValueColumn = trimmedStartColumn + Math.max(valueOffset, 0);\n\n const typeAndAttributeSplit = splitTypeAndAttributes(declarationValue);\n const typeSource = typeAndAttributeSplit.typeSource.trim();\n const attributeSource = typeAndAttributeSplit.attributeSource.trimStart();\n const leadingAttributeWhitespace =\n typeAndAttributeSplit.attributeSource.length - attributeSource.length;\n\n const typeConstructor = parseTypeConstructorCall(context, {\n declarationValue: typeSource,\n lineIndex,\n startColumn: declarationValueColumn,\n invalidCode: 'PSL_INVALID_TYPES_MEMBER',\n invalidMessage: (value) => `Invalid types declaration \"${value}\"`,\n });\n if (typeConstructor === 'malformed') {\n continue;\n }\n\n const attributeParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n attributeSource,\n declarationValueColumn + typeAndAttributeSplit.attributeOffset + leadingAttributeWhitespace,\n );\n if (!attributeParse.ok) {\n continue;\n }\n const attributes = attributeParse.tokens\n .map((token) =>\n parseAttributeToken(context, {\n token: token.text,\n target: 'namedType',\n lineIndex,\n span: token.span,\n }),\n )\n .filter((attribute): attribute is PslAttribute => Boolean(attribute));\n\n if (typeConstructor) {\n declarations.push({\n kind: 'namedType',\n name: declarationName,\n typeConstructor,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const baseTypeMatch = typeSource.match(/^([A-Za-z_]\\w*)$/);\n if (!baseTypeMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_TYPES_MEMBER',\n message: `Invalid types declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const baseType = baseTypeMatch[1] ?? '';\n\n declarations.push({\n kind: 'namedType',\n name: declarationName,\n baseType,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n }\n\n return {\n kind: 'types',\n declarations,\n span: createLineRangeSpan(context, bounds.startLine, bounds.endLine),\n };\n}\n\nfunction parseTypeConstructorCall(\n context: ParserContext,\n input: {\n readonly declarationValue: string;\n readonly lineIndex: number;\n readonly startColumn: number;\n readonly invalidCode: PslDiagnosticCode;\n readonly invalidMessage: (value: string) => string;\n },\n): PslTypeConstructorCall | 'malformed' | undefined {\n const value = input.declarationValue.trim();\n const constructorMatch = value.match(\n /^([A-Za-z_][A-Za-z0-9_-]*(?:\\.[A-Za-z_][A-Za-z0-9_-]*)*)\\s*\\(/,\n );\n if (!constructorMatch) {\n return undefined;\n }\n\n // constructorMatch already required `(`; openParen is guaranteed ≥ 0.\n const openParen = value.indexOf('(');\n const closeParen = value.lastIndexOf(')');\n\n if (closeParen !== value.length - 1) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidMessage(value),\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n });\n return 'malformed';\n }\n\n const constructorPath = constructorMatch[1] ?? '';\n\n const argsRaw = value.slice(openParen + 1, closeParen);\n const args = parseArgumentList(context, {\n argsRaw,\n argsOffset: input.startColumn + openParen + 1,\n lineIndex: input.lineIndex,\n token: value,\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n invalidCode: input.invalidCode,\n invalidEmptyArgumentMessage: `Invalid empty argument in type constructor \"${value}\"`,\n invalidNamedArgumentMessage: (part) =>\n `Invalid named argument syntax \"${part}\" in type constructor \"${value}\"`,\n });\n if (!args) {\n return 'malformed';\n }\n\n return {\n kind: 'typeConstructor',\n path: constructorPath.split('.'),\n args,\n span: createInlineSpan(\n context,\n input.lineIndex,\n input.startColumn,\n input.startColumn + value.length,\n ),\n };\n}\n\nfunction parseModelAttribute(\n context: ParserContext,\n line: string,\n lineIndex: number,\n): PslModelAttribute | undefined {\n const rawLine = context.lines[lineIndex] ?? '';\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n line,\n firstNonWhitespaceColumn(rawLine),\n );\n if (!tokenParse.ok || tokenParse.tokens.length !== 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid model attribute syntax \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n const token = tokenParse.tokens[0];\n if (!token) {\n return undefined;\n }\n return parseAttributeToken(context, {\n token: token.text,\n target: 'model',\n lineIndex,\n span: token.span,\n });\n}\n\nfunction parseEnumAttribute(\n context: ParserContext,\n line: string,\n lineIndex: number,\n): PslAttribute | undefined {\n const rawLine = context.lines[lineIndex] ?? '';\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n line,\n firstNonWhitespaceColumn(rawLine),\n );\n if (!tokenParse.ok || tokenParse.tokens.length !== 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n const token = tokenParse.tokens[0];\n if (!token) {\n return undefined;\n }\n const parsed = parseAttributeToken(context, {\n token: token.text,\n target: 'enum',\n lineIndex,\n span: token.span,\n });\n if (!parsed) {\n return undefined;\n }\n if (parsed.name !== 'map') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ENUM_MEMBER',\n message: `Invalid enum value declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n return parsed;\n}\n\nfunction parseField(context: ParserContext, line: string, lineIndex: number): PslField | undefined {\n const fieldMatch = line.match(/^([A-Za-z_]\\w*)(\\s+)(.+)$/);\n if (!fieldMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n\n const fieldName = fieldMatch[1] ?? '';\n const separator = fieldMatch[2] ?? '';\n const remainder = fieldMatch[3] ?? '';\n const typeAndAttributeSplit = splitTypeAndAttributes(remainder);\n const rawTypeSource = typeAndAttributeSplit.typeSource.trim();\n const attributePart = typeAndAttributeSplit.attributeSource;\n const optional = rawTypeSource.endsWith('?');\n const typeSourceWithoutOptional = optional ? rawTypeSource.slice(0, -1).trimEnd() : rawTypeSource;\n const list = typeSourceWithoutOptional.endsWith('[]');\n const baseTypeSource = list\n ? typeSourceWithoutOptional.slice(0, -2).trimEnd()\n : typeSourceWithoutOptional;\n const rawLine = context.lines[lineIndex] ?? '';\n const trimmedStartColumn = firstNonWhitespaceColumn(rawLine);\n const typeStartColumn = trimmedStartColumn + fieldName.length + separator.length;\n\n const typeConstructor = parseTypeConstructorCall(context, {\n declarationValue: baseTypeSource,\n lineIndex,\n startColumn: typeStartColumn,\n invalidCode: 'PSL_INVALID_MODEL_MEMBER',\n invalidMessage: (value) => `Invalid field type constructor \"${value}\"`,\n });\n if (typeConstructor === 'malformed') {\n return undefined;\n }\n\n let typeName: string;\n let typeNamespaceId: string | undefined;\n let typeContractSpaceId: string | undefined;\n\n if (typeConstructor) {\n typeName = typeConstructor.path.join('.');\n } else {\n // Detect the colon-prefix cross-contract-space form: `<space>:<rest>` where\n // `<rest>` is the existing dot-qualified or bare form (`<ns>.<Name>` or `<Name>`).\n // Multiple colons (e.g. `a:b:c`) are invalid.\n const colonCount = (baseTypeSource.match(/:/g) ?? []).length;\n if (colonCount > 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n\n let typeRefSource: string;\n if (colonCount === 1) {\n // Colon-prefix form: `<space>:<rest>`\n const colonIndex = baseTypeSource.indexOf(':');\n const spaceCandidate = baseTypeSource.slice(0, colonIndex);\n typeRefSource = baseTypeSource.slice(colonIndex + 1);\n // Validate space identifier\n if (!/^[A-Za-z_]\\w*$/.test(spaceCandidate)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n typeContractSpaceId = spaceCandidate;\n } else {\n typeRefSource = baseTypeSource;\n }\n\n const dotCount = (typeRefSource.match(/\\./g) ?? []).length;\n if (dotCount > 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_QUALIFIED_TYPE',\n message: `Nested dot-qualified type \"${baseTypeSource}\" is not supported; use exactly one qualifier segment (e.g. \"ns.TypeName\")`,\n span: createInlineSpan(\n context,\n lineIndex,\n typeStartColumn,\n typeStartColumn + baseTypeSource.length,\n ),\n });\n return undefined;\n }\n const singleMatch = typeRefSource.match(/^([A-Za-z_]\\w*)(?:\\.([A-Za-z_]\\w*))?$/);\n if (!singleMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_MODEL_MEMBER',\n message: `Invalid model member declaration \"${line}\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n return undefined;\n }\n if (singleMatch[2] !== undefined) {\n typeNamespaceId = singleMatch[1];\n typeName = singleMatch[2];\n } else {\n typeName = singleMatch[1] ?? '';\n }\n }\n\n const attributes: PslFieldAttribute[] = [];\n const attributeSource = attributePart.trimStart();\n const leadingAttributeWhitespace = attributePart.length - attributeSource.length;\n const tokenParse = extractAttributeTokensWithSpans(\n context,\n lineIndex,\n attributeSource,\n trimmedStartColumn +\n fieldName.length +\n separator.length +\n typeAndAttributeSplit.attributeOffset +\n leadingAttributeWhitespace,\n );\n if (!tokenParse.ok) {\n return {\n kind: 'field',\n name: fieldName,\n typeName,\n ...ifDefined('typeNamespaceId', typeNamespaceId),\n ...ifDefined('typeContractSpaceId', typeContractSpaceId),\n ...ifDefined('typeConstructor', typeConstructor),\n optional,\n list,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n }\n\n for (const token of tokenParse.tokens) {\n const parsed = parseAttributeToken(context, {\n token: token.text,\n target: 'field',\n lineIndex,\n span: token.span,\n });\n if (parsed) {\n attributes.push(parsed);\n }\n }\n\n return {\n kind: 'field',\n name: fieldName,\n typeName,\n ...ifDefined('typeNamespaceId', typeNamespaceId),\n ...ifDefined('typeContractSpaceId', typeContractSpaceId),\n ...ifDefined('typeConstructor', typeConstructor),\n optional,\n list,\n attributes,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n}\n\nfunction isQuoteEscaped(value: string, quoteIndex: number): boolean {\n let backslashCount = 0;\n\n for (let index = quoteIndex - 1; index >= 0 && value[index] === '\\\\'; index -= 1) {\n backslashCount += 1;\n }\n\n return backslashCount % 2 === 1;\n}\n\nfunction splitTypeAndAttributes(value: string): {\n readonly typeSource: string;\n readonly attributeSource: string;\n readonly attributeOffset: number;\n} {\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n let quote: '\"' | \"'\" | null = null;\n\n for (let index = 0; index < value.length; index += 1) {\n const character = value[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === '(') {\n depthParen += 1;\n continue;\n }\n if (character === ')') {\n depthParen = Math.max(0, depthParen - 1);\n continue;\n }\n if (character === '[') {\n depthBracket += 1;\n continue;\n }\n if (character === ']') {\n depthBracket = Math.max(0, depthBracket - 1);\n continue;\n }\n if (character === '{') {\n depthBrace += 1;\n continue;\n }\n if (character === '}') {\n depthBrace = Math.max(0, depthBrace - 1);\n continue;\n }\n\n if (character === '@' && depthParen === 0 && depthBracket === 0 && depthBrace === 0) {\n return {\n typeSource: value.slice(0, index).trimEnd(),\n attributeSource: value.slice(index),\n attributeOffset: index,\n };\n }\n }\n\n return {\n typeSource: value.trimEnd(),\n attributeSource: '',\n attributeOffset: value.length,\n };\n}\n\nfunction parseAttributeToken(\n context: ParserContext,\n input: {\n readonly token: string;\n readonly target: PslAttributeTarget;\n readonly lineIndex: number;\n readonly span: PslSpan;\n },\n): PslAttribute | undefined {\n const expectsBlockPrefix = input.target === 'model' || input.target === 'enum';\n const targetLabel = input.target === 'enum' ? 'Enum' : 'Model';\n if (expectsBlockPrefix && !input.token.startsWith('@@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `${targetLabel} attribute \"${input.token}\" must use @@ prefix`,\n span: input.span,\n });\n return undefined;\n }\n if (!expectsBlockPrefix && !input.token.startsWith('@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Attribute \"${input.token}\" must use @ prefix`,\n span: input.span,\n });\n return undefined;\n }\n if (!expectsBlockPrefix && input.token.startsWith('@@')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Attribute \"${input.token}\" is not valid in ${input.target} context`,\n span: input.span,\n });\n return undefined;\n }\n\n const rawBody = expectsBlockPrefix ? input.token.slice(2) : input.token.slice(1);\n const openParen = rawBody.indexOf('(');\n const closeParen = rawBody.lastIndexOf(')');\n const hasArgs = openParen >= 0 || closeParen >= 0;\n if ((openParen >= 0 && closeParen === -1) || (openParen === -1 && closeParen >= 0)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n\n const name = (openParen >= 0 ? rawBody.slice(0, openParen) : rawBody).trim();\n if (!/^[A-Za-z_][A-Za-z0-9_-]*(\\.[A-Za-z_][A-Za-z0-9_-]*)*$/.test(name)) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute name \"${name || input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n\n let args: readonly PslAttributeArgument[] = [];\n if (hasArgs && openParen >= 0 && closeParen >= openParen) {\n if (closeParen !== rawBody.length - 1) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid trailing syntax in attribute \"${input.token}\"`,\n span: input.span,\n });\n return undefined;\n }\n const argsRaw = rawBody.slice(openParen + 1, closeParen);\n const parsedArgs = parseArgumentList(context, {\n argsRaw,\n argsOffset: input.span.start.column - 1 + (expectsBlockPrefix ? 2 : 1) + openParen + 1,\n lineIndex: input.lineIndex,\n token: input.token,\n span: input.span,\n invalidCode: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n invalidEmptyArgumentMessage: `Invalid empty argument in attribute \"${input.token}\"`,\n invalidNamedArgumentMessage: (part) => `Invalid named argument syntax \"${part}\"`,\n });\n if (!parsedArgs) {\n return undefined;\n }\n args = parsedArgs;\n }\n\n return {\n kind: 'attribute',\n target: input.target,\n name,\n args,\n span: input.span,\n };\n}\n\nfunction parseArgumentList(\n context: ParserContext,\n input: {\n readonly argsRaw: string;\n readonly argsOffset: number;\n readonly lineIndex: number;\n readonly token: string;\n readonly span: PslSpan;\n readonly invalidCode: PslDiagnosticCode;\n readonly invalidEmptyArgumentMessage: string;\n readonly invalidNamedArgumentMessage: (part: string) => string;\n },\n): readonly PslAttributeArgument[] | undefined {\n const trimmed = input.argsRaw.trim();\n if (trimmed.length === 0) {\n return [];\n }\n\n const parts = splitTopLevelSegments(input.argsRaw, ',');\n const args: PslAttributeArgument[] = [];\n\n for (const part of parts) {\n const original = part.value;\n const trimmedPart = original.trim();\n if (trimmedPart.length === 0) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidEmptyArgumentMessage,\n span: input.span,\n });\n return undefined;\n }\n\n const leadingWhitespace = original.length - original.trimStart().length;\n const partStart = input.argsOffset + part.start + leadingWhitespace;\n const partEnd = partStart + trimmedPart.length;\n const partSpan = createInlineSpan(context, input.lineIndex, partStart, partEnd);\n\n const namedSplit = splitTopLevelSegments(trimmedPart, ':');\n if (namedSplit.length > 1) {\n const first = namedSplit[0];\n if (!first) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidNamedArgumentMessage(trimmedPart),\n span: partSpan,\n });\n return undefined;\n }\n const name = first.value.trim();\n const rawValue = trimmedPart.slice(first.end + 1).trim();\n if (!name || rawValue.length === 0) {\n pushDiagnostic(context, {\n code: input.invalidCode,\n message: input.invalidNamedArgumentMessage(trimmedPart),\n span: partSpan,\n });\n return undefined;\n }\n args.push({\n kind: 'named',\n name,\n value: normalizeAttributeArgumentValue(rawValue),\n span: partSpan,\n });\n continue;\n }\n\n args.push({\n kind: 'positional',\n value: normalizeAttributeArgumentValue(trimmedPart),\n span: partSpan,\n });\n }\n\n return args;\n}\n\nfunction normalizeAttributeArgumentValue(value: string): string {\n return value.trim();\n}\n\nfunction findBlockBounds(context: ParserContext, startLine: number): BlockBounds {\n let depth = 0;\n\n for (let lineIndex = startLine; lineIndex < context.lines.length; lineIndex += 1) {\n const line = stripInlineComment(context.lines[lineIndex] ?? '');\n let quote: '\"' | \"'\" | null = null;\n for (let index = 0; index < line.length; index += 1) {\n const character = line[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(line, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n\n if (character === '{') {\n depth += 1;\n }\n if (character === '}') {\n depth -= 1;\n if (depth === 0) {\n return { startLine, endLine: lineIndex, closed: true };\n }\n }\n }\n }\n\n pushDiagnostic(context, {\n code: 'PSL_UNTERMINATED_BLOCK',\n message: 'Unterminated block declaration',\n span: createTrimmedLineSpan(context, startLine),\n });\n return {\n startLine,\n endLine: context.lines.length - 1,\n closed: false,\n };\n}\n\ninterface TopLevelSegment {\n readonly value: string;\n readonly start: number;\n readonly end: number;\n}\n\nfunction splitTopLevelSegments(value: string, separator: ',' | ':'): TopLevelSegment[] {\n const parts: TopLevelSegment[] = [];\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n let quote: '\"' | \"'\" | null = null;\n let start = 0;\n\n for (let index = 0; index < value.length; index += 1) {\n const character = value[index] ?? '';\n if (quote) {\n if (character === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n continue;\n }\n\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n\n if (character === '(') {\n depthParen += 1;\n continue;\n }\n if (character === ')') {\n depthParen = Math.max(0, depthParen - 1);\n continue;\n }\n if (character === '[') {\n depthBracket += 1;\n continue;\n }\n if (character === ']') {\n depthBracket = Math.max(0, depthBracket - 1);\n continue;\n }\n if (character === '{') {\n depthBrace += 1;\n continue;\n }\n if (character === '}') {\n depthBrace = Math.max(0, depthBrace - 1);\n continue;\n }\n\n if (character === separator && depthParen === 0 && depthBracket === 0 && depthBrace === 0) {\n parts.push({\n value: value.slice(start, index),\n start,\n end: index,\n });\n start = index + 1;\n }\n }\n\n parts.push({\n value: value.slice(start),\n start,\n end: value.length,\n });\n return parts;\n}\n\nfunction extractAttributeTokensWithSpans(\n context: ParserContext,\n lineIndex: number,\n value: string,\n startColumn: number,\n): { readonly ok: boolean; readonly tokens: readonly { text: string; span: PslSpan }[] } {\n const tokens: { text: string; span: PslSpan }[] = [];\n let index = 0;\n while (index < value.length) {\n while (index < value.length && /\\s/.test(value[index] ?? '')) {\n index += 1;\n }\n if (index >= value.length) {\n break;\n }\n\n if (value[index] !== '@') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + index, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n const start = index;\n index += 1;\n if (value[index] === '@') {\n index += 1;\n }\n\n const nameStart = index;\n while (index < value.length && /[A-Za-z0-9_.-]/.test(value[index] ?? '')) {\n index += 1;\n }\n\n if (index === nameStart) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.slice(start).trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + start, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n if (value[index] === '(') {\n let depth = 0;\n let quote: '\"' | \"'\" | null = null;\n while (index < value.length) {\n const char = value[index] ?? '';\n if (quote) {\n if (char === quote && !isQuoteEscaped(value, index)) {\n quote = null;\n }\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n\n if (char === '(') {\n depth += 1;\n } else if (char === ')') {\n depth -= 1;\n if (depth === 0) {\n index += 1;\n break;\n }\n }\n index += 1;\n }\n if (depth !== 0) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Unterminated attribute argument list in \"${value.slice(start).trim()}\"`,\n span: createInlineSpan(\n context,\n lineIndex,\n startColumn + start,\n startColumn + value.length,\n ),\n });\n return { ok: false, tokens };\n }\n }\n\n const tokenText = value.slice(start, index).trim();\n tokens.push({\n text: tokenText,\n span: createInlineSpan(context, lineIndex, startColumn + start, startColumn + index),\n });\n\n while (index < value.length && /\\s/.test(value[index] ?? '')) {\n index += 1;\n }\n\n if (index < value.length && value[index] !== '@') {\n break;\n }\n }\n\n if (index < value.length && value[index] !== '@') {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_ATTRIBUTE_SYNTAX',\n message: `Invalid attribute syntax \"${value.trim()}\"`,\n span: createInlineSpan(context, lineIndex, startColumn + index, startColumn + value.length),\n });\n return { ok: false, tokens };\n }\n\n return { ok: true, tokens };\n}\n\nfunction stripInlineComment(line: string): string {\n let quote: '\"' | \"'\" | null = null;\n for (let index = 0; index < line.length - 1; index += 1) {\n const current = line[index] ?? '';\n const next = line[index + 1] ?? '';\n\n if (quote) {\n if (current === quote && !isQuoteEscaped(line, index)) {\n quote = null;\n }\n continue;\n }\n\n if (current === '\"' || current === \"'\") {\n quote = current;\n continue;\n }\n\n if (current === '/' && next === '/') {\n return line.slice(0, index);\n }\n }\n\n return line;\n}\n\nfunction computeLineOffsets(schema: string): number[] {\n const offsets = [0];\n for (let index = 0; index < schema.length; index += 1) {\n if (schema[index] === '\\n') {\n offsets.push(index + 1);\n }\n }\n return offsets;\n}\n\nfunction firstNonWhitespaceColumn(line: string): number {\n const first = line.search(/\\S/);\n return first === -1 ? 0 : first;\n}\n\nfunction createInlineSpan(\n context: ParserContext,\n lineIndex: number,\n startColumn: number,\n endColumn: number,\n): PslSpan {\n return {\n start: createPosition(context, lineIndex, startColumn),\n end: createPosition(context, lineIndex, endColumn),\n };\n}\n\nfunction createTrimmedLineSpan(context: ParserContext, lineIndex: number): PslSpan {\n const line = context.lines[lineIndex] ?? '';\n const startColumn = firstNonWhitespaceColumn(line);\n return {\n start: createPosition(context, lineIndex, startColumn),\n end: createPosition(context, lineIndex, line.length),\n };\n}\n\nfunction createLineRangeSpan(context: ParserContext, startLine: number, endLine: number): PslSpan {\n const startLineText = context.lines[startLine] ?? '';\n const endLineText = context.lines[endLine] ?? '';\n const startColumn = firstNonWhitespaceColumn(startLineText);\n return {\n start: createPosition(context, startLine, startColumn),\n end: createPosition(context, endLine, endLineText.length),\n };\n}\n\nfunction createPosition(\n context: ParserContext,\n lineIndex: number,\n columnIndex: number,\n): PslPosition {\n const clampedLineIndex = Math.max(0, Math.min(lineIndex, context.lineOffsets.length - 1));\n const lineText = context.lines[clampedLineIndex] ?? '';\n const clampedColumnIndex = Math.max(0, Math.min(columnIndex, lineText.length));\n return {\n offset: (context.lineOffsets[clampedLineIndex] ?? 0) + clampedColumnIndex,\n line: clampedLineIndex + 1,\n column: clampedColumnIndex + 1,\n };\n}\n\nfunction pushDiagnostic(\n context: ParserContext,\n diagnostic: Omit<PslDiagnostic, 'sourceId'> & { readonly code: PslDiagnosticCode },\n): void {\n context.diagnostics.push({\n ...diagnostic,\n sourceId: context.sourceId,\n });\n}\n\nfunction lookupExtensionBlockDescriptor(\n namespace: AuthoringPslBlockDescriptorNamespace,\n keyword: string,\n): AuthoringPslBlockDescriptor | undefined {\n if (!Object.hasOwn(namespace, keyword)) {\n return undefined;\n }\n const value = namespace[keyword];\n return isAuthoringPslBlockDescriptor(value) ? value : undefined;\n}\n\n/**\n * Reads an extension block body generically, driven by the descriptor's\n * `parameters` map. Each `key = <rhs>` line in the body is matched against\n * a declared parameter and the RHS is captured per the parameter's kind:\n *\n * - `ref` → the bareword identifier token (`PslExtensionBlockParamRef`)\n * - `value` → the raw RHS text verbatim (`PslExtensionBlockParamScalarValue`)\n * - `option` → the chosen bareword token (`PslExtensionBlockParamOption`)\n * - `list` → bracketed `[a, b, …]` list, each element captured per `of`\n * (`PslExtensionBlockParamList`)\n *\n * No validation runs here (unknown key, missing required, codec acceptance,\n * option-in-set, ref resolution). A body line that is not `key = value`\n * shaped emits a `PSL_INVALID_EXTENSION_BLOCK_MEMBER` parse diagnostic.\n */\nfunction parseExtensionBlock(\n context: ParserContext,\n descriptor: AuthoringPslBlockDescriptor,\n blockName: string,\n keywordLineIndex: number,\n bounds: BlockBounds,\n): PslExtensionBlock {\n const parameters: Record<string, PslExtensionBlockParamValue> = {};\n\n for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {\n const raw = context.lines[lineIndex] ?? '';\n const line = stripInlineComment(raw).trim();\n if (line.length === 0) {\n continue;\n }\n\n const assignMatch = line.match(/^([A-Za-z_]\\w*)\\s*=\\s*(.+)$/);\n if (!assignMatch) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Invalid extension block body line \"${line}\"; expected \"key = value\"`,\n span: createTrimmedLineSpan(context, lineIndex),\n });\n continue;\n }\n\n const key = assignMatch[1] ?? '';\n const rhsRaw = (assignMatch[2] ?? '').trim();\n const paramDescriptor = descriptor.parameters[key];\n\n if (paramDescriptor === undefined) {\n // Unknown parameter — captured as a raw value; the generic validator reports this.\n parameters[key] = {\n kind: 'value',\n raw: rhsRaw,\n span: createTrimmedLineSpan(context, lineIndex),\n };\n continue;\n }\n\n const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);\n if (captured !== undefined) {\n parameters[key] = captured;\n }\n }\n\n return {\n kind: descriptor.discriminator,\n name: blockName,\n parameters,\n span: createLineRangeSpan(context, keywordLineIndex, bounds.endLine),\n };\n}\n\n/**\n * Captures a single parameter RHS string according to the declared parameter\n * kind. Returns `undefined` and pushes a diagnostic only if the syntax is\n * genuinely malformed (e.g. a `list` with no opening bracket). Value\n * acceptance (codec, option-in-set, ref resolution) is handled by the validator.\n */\nfunction captureParamRhs(\n context: ParserContext,\n lineIndex: number,\n rhs: string,\n param: AuthoringPslBlockDescriptor['parameters'][string],\n): PslExtensionBlockParamValue | undefined {\n const span = createTrimmedLineSpan(context, lineIndex);\n\n switch (param.kind) {\n case 'ref': {\n return { kind: 'ref', identifier: rhs, span };\n }\n case 'value': {\n return { kind: 'value', raw: rhs, span };\n }\n case 'option': {\n return { kind: 'option', token: rhs, span };\n }\n case 'list': {\n if (!rhs.startsWith('[') || !rhs.endsWith(']')) {\n pushDiagnostic(context, {\n code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',\n message: `Expected a bracketed list \"[…]\" for list parameter, got \"${rhs}\"`,\n span,\n });\n return undefined;\n }\n const inner = rhs.slice(1, -1).trim();\n const items: PslExtensionBlockParamValue[] = [];\n if (inner.length > 0) {\n const segments = splitTopLevelSegments(inner, ',');\n for (const segment of segments) {\n const itemRhs = segment.value.trim();\n if (itemRhs.length === 0) {\n continue;\n }\n const item = captureParamRhs(context, lineIndex, itemRhs, param.of);\n if (item !== undefined) {\n items.push(item);\n }\n }\n }\n return { kind: 'list', items, span };\n }\n }\n}\n"],"mappings":"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"}