@cratis/screenplay-language 4.55.1 → 4.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/AnalysisCommand.d.ts +16 -0
  2. package/dist/AnalysisCommand.d.ts.map +1 -0
  3. package/dist/AnalysisDiagnostic.d.ts +8 -0
  4. package/dist/AnalysisDiagnostic.d.ts.map +1 -0
  5. package/dist/AnalysisLocation.d.ts +6 -0
  6. package/dist/AnalysisLocation.d.ts.map +1 -0
  7. package/dist/AnalysisSpecification.d.ts +16 -0
  8. package/dist/AnalysisSpecification.d.ts.map +1 -0
  9. package/dist/AnalysisType.d.ts +6 -0
  10. package/dist/AnalysisType.d.ts.map +1 -0
  11. package/dist/AuthoringDocument.d.ts +6 -0
  12. package/dist/AuthoringDocument.d.ts.map +1 -0
  13. package/dist/CommandResponseSymbol.d.ts +13 -0
  14. package/dist/CommandResponseSymbol.d.ts.map +1 -0
  15. package/dist/ResponseAnalysis.d.ts +9 -0
  16. package/dist/ResponseAnalysis.d.ts.map +1 -0
  17. package/dist/ResponseFieldSymbol.d.ts +10 -0
  18. package/dist/ResponseFieldSymbol.d.ts.map +1 -0
  19. package/dist/ResponseSourceSymbol.d.ts +6 -0
  20. package/dist/ResponseSourceSymbol.d.ts.map +1 -0
  21. package/dist/bundles/chunk-IZGYM33T.js +14 -0
  22. package/dist/bundles/chunk-IZGYM33T.js.map +7 -0
  23. package/dist/bundles/index.js +18 -1362
  24. package/dist/bundles/index.js.map +4 -4
  25. package/dist/bundles/sub-languages/capture/index.js +35 -672
  26. package/dist/bundles/sub-languages/capture/index.js.map +1 -1
  27. package/dist/bundles/sub-languages/projection/index.js +53 -1625
  28. package/dist/bundles/sub-languages/projection/index.js.map +1 -1
  29. package/dist/completion-items.d.ts +1 -0
  30. package/dist/completion-items.d.ts.map +1 -1
  31. package/dist/completion-planner.d.ts.map +1 -1
  32. package/dist/completions.d.ts +2 -0
  33. package/dist/completions.d.ts.map +1 -1
  34. package/dist/diagnostic-codes.d.ts +14 -0
  35. package/dist/diagnostic-codes.d.ts.map +1 -1
  36. package/dist/hover-content.d.ts.map +1 -1
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/keyword-docs.d.ts +4 -0
  40. package/dist/keyword-docs.d.ts.map +1 -1
  41. package/dist/response-analysis.d.ts +15 -0
  42. package/dist/response-analysis.d.ts.map +1 -0
  43. package/dist/response-completions.d.ts +4 -0
  44. package/dist/response-completions.d.ts.map +1 -0
  45. package/dist/response-tokens.d.ts +8 -0
  46. package/dist/response-tokens.d.ts.map +1 -0
  47. package/dist/symbols.d.ts +11 -0
  48. package/dist/symbols.d.ts.map +1 -1
  49. package/dist/tokens.d.ts.map +1 -1
  50. package/dist/validation.d.ts +3 -0
  51. package/dist/validation.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/dist/bundles/chunk-LXM5L4YK.js +0 -4893
  54. package/dist/bundles/chunk-LXM5L4YK.js.map +0 -7
@@ -1,1647 +1,75 @@
1
- import {
2
- describeEventContext,
3
- describeEventContextMember,
4
- eventContextMemberAt,
5
- eventContextMembers,
6
- eventContextMembersAfter,
7
- fenceMap,
8
- validateEventContextPaths
9
- } from "../../chunk-LXM5L4YK.js";
1
+ import{describeEventContext,describeEventContextMember,eventContextMemberAt,eventContextMembers,eventContextMembersAfter,fenceMap,validateEventContextPaths}from"../../chunk-IZGYM33T.js";var languageId="pdl",KEYWORDS=["projection","sequence","all","every","on","from","key","parent","join","automap","no","children","nested","identified","by","add","subtract","remove","via","with","default","increment","decrement","count","set","unset","clear","events","id","exclude","variant","enters"],BUILTINS=["$eventSourceId","$causedBy","$eventContext"],OPERATORS=["=","+=","-=","=>","."],configuration={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}],indentationRules:{increaseIndentPattern:/^.*(:|\bon\b|\ball\b|\bevery\b|\bchildren\b|\bnested\b|\bparent\b|\bvariant\b)\s*$/,decreaseIndentPattern:/^.*\}.*$/},folding:{offSide:!0,markers:{start:/^\s*(projection|all|every|on|children|nested|parent|variant)/,end:/^\s*$/}},wordPattern:/@?[a-zA-Z_$][\w$-]*/},monarchLanguage={defaultToken:"",tokenPostfix:".pdl",keywords:KEYWORDS,builtins:BUILTINS,operators:OPERATORS,symbols:/[=><!~?:&|+\-*/^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[{include:"@whitespace"},[/`/,{token:"string.template",next:"@templateString"}],[/@[a-zA-Z_$][\w$]*/,"identifier.escape"],[/[A-Z][a-zA-Z_$][\w$]*/,{cases:{"@keywords":"invalid","@default":"identifier"}}],[/[a-z_$][\w$]*/,{cases:{"@keywords":"keyword","@builtins":"variable.predefined","@default":"identifier"}}],[/[{}()[\]]/,"@brackets"],[/=>/,"operator.arrow"],[/@symbols/,{cases:{"@operators":"operator","@default":""}}],[/\d*\.\d+([eE][-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F]+/,"number.hex"],[/\d+/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,{token:"string.quote",next:"@string"}]],whitespace:[[/[ \t\r\n]+/,""],[/#.*$/,"comment"]],templateString:[[/\$\{/,{token:"delimiter.bracket",next:"@templateExpression"}],[/[^\\`$]+/,"string.template"],[/@escapes/,"string.template.escape"],[/\\./,"string.template.escape.invalid"],[/`/,{token:"string.template",next:"@pop"}]],templateExpression:[[/\}/,{token:"delimiter.bracket",next:"@pop"}],{include:"@root"}],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",next:"@pop"}]]}};var EVENT_CONTEXT_PATH=/\$eventContext\.((?:\w+\.)*)(\w*)$/,CompletionProvider=class{readModels=[];eventSchemas={};eventSequences=[];setReadModels(readModels){this.readModels=readModels||[]}setEventSequences(sequences){this.eventSequences=sequences||[]}setReadModelSchemas(schemas){this.readModels=schemas.map(schema=>({identifier:this.getSchemaName(schema)||"",displayName:this.getSchemaName(schema)||"",schema}))}setEventSchemas(schemas){if(!schemas){this.eventSchemas={};return}if(Array.isArray(schemas)){let map={};schemas.forEach((s,i)=>{if(!s)return;let name=this.getSchemaName(s)||`Event${i+1}`;map[name]=s}),this.eventSchemas=map;return}this.eventSchemas=schemas}provideCompletionItems(model,position){let context=this.buildContext(model,position),suggestions=[],activeSchema=this.getActiveReadModelSchema(model);return context.lineNumber===1?this.addProjectionLineCompletions(suggestions,context):this.isAfterKeyword(context,"sequence")?this.addEventSequenceCompletions(suggestions,context):this.isAfterKeyword(context,"from")||this.isAfterKeyword(context,"every")?this.addEventTypeCompletions(suggestions,context):/\benters\s+on\s+\w*$/.test(context.textBeforeCursor)?this.addEventTypeCompletions(suggestions,context):/\benters\s+\w*$/.test(context.textBeforeCursor)?suggestions.push({label:"on",kind:14,insertText:"on ",documentation:"Declares the event that activates this variant.",detail:"enters on <EventType>",range:this.getRangeForWord(context)}):this.isAfterKeyword(context,"variant")?this.addVariantNameCompletions(suggestions,context):this.isAfterKeyword(context,"key")?this.addKeyCompletions(suggestions,context,activeSchema):this.isAfterKeyword(context,"parent")?this.addParentCompletions(suggestions,context):this.isAfterKeyword(context,"children")?this.addChildrenCompletions(suggestions,context,activeSchema):this.isAfterKeyword(context,"join")?this.addJoinCompletions(suggestions,context,activeSchema):this.isAfterKeyword(context,"with")?this.addEventTypeCompletions(suggestions,context):this.isAfterNumericOperationKeyword(context)?this.addNumericPropertyCompletions(suggestions,context,activeSchema):this.isAfterAddOrSubtractBy(context)?this.addAssignmentValueCompletions(suggestions,context,model,position):this.isInAssignment(context)?this.addAssignmentValueCompletions(suggestions,context,model,position):this.isPropertyDotAccess(context)?this.addPropertyMemberCompletions(suggestions,context):(this.isStartOfLine(context)||this.isAfterIndent(context))&&this.addStatementCompletions(suggestions,context,activeSchema),{suggestions}}buildContext(model,position){let lineContent=model.getLineContent(position.lineNumber),textBeforeCursor=lineContent.substring(0,position.column-1),textAfterCursor=lineContent.substring(position.column-1),currentWord=model.getWordAtPosition(position)?.word||"",indentLevel=this.getIndentLevel(textBeforeCursor);return{lineContent,textBeforeCursor,textAfterCursor,currentWord,indentLevel,lineNumber:position.lineNumber}}getIndentLevel(text){let match=text.match(/^(\s*)/);return match?Math.floor(match[1].length/2):0}isStartOfLine(context){return context.textBeforeCursor.trim()===""}isAfterIndent(context){return/^\s+$/.test(context.textBeforeCursor)}isAfterKeyword(context,keyword){return new RegExp(`\\b${keyword}\\s+\\w*$`).test(context.textBeforeCursor)}isAfterNumericOperationKeyword(context){let countIncrDecrPattern=/\b(count|increment|decrement)\s+\w*$/,addSubtractPattern=/\b(add|subtract)\s+\w*$/;return countIncrDecrPattern.test(context.textBeforeCursor)?!0:addSubtractPattern.test(context.textBeforeCursor)?!this.isAfterAddOrSubtractBy(context):!1}isAfterAddOrSubtractBy(context){return/\b(add|subtract)\s+\w+\s+by\s+\w*$/.test(context.textBeforeCursor)}isInAssignment(context){return/\w+\s*=\s*\w*$/.test(context.textBeforeCursor)}isPropertyDotAccess(context){return/(\w+|\$\w+)\.(\w*)$/.test(context.textBeforeCursor)||EVENT_CONTEXT_PATH.test(context.textBeforeCursor)}addProjectionLineCompletions(suggestions,context){let trimmed=context.textBeforeCursor.trim();(trimmed===""||"projection".startsWith(trimmed))&&suggestions.push({label:"projection",kind:14,insertText:"projection ",documentation:"Define a projection that transforms events into a read model",detail:"projection <ProjectionName>",range:this.getRangeForWord(context)});let arrowMatch=trimmed.match(/^projection\s+[\w.]+\s*=>\s*([\w.]*)$/);if(arrowMatch){let partialReadModel=arrowMatch[1]||"";this.readModels.forEach(readModel=>{if(!partialReadModel||readModel.displayName.toLowerCase().startsWith(partialReadModel.toLowerCase())){let label=`${readModel.displayName} (${readModel.identifier})`;suggestions.push({label,kind:6,insertText:readModel.displayName,filterText:`${readModel.displayName} ${readModel.identifier}`,documentation:`Read model: ${readModel.displayName} (${readModel.identifier})`,detail:readModel.identifier,range:this.getRangeForWord(context)})}});return}if(trimmed.startsWith("projection ")&&!trimmed.includes("=>")){let afterProjection=trimmed.substring(11);this.readModels.forEach(readModel=>{if(!afterProjection||readModel.displayName.toLowerCase().startsWith(afterProjection.toLowerCase())){let label=`${readModel.displayName} (${readModel.identifier})`;suggestions.push({label,kind:6,insertText:`${readModel.displayName} => ${readModel.displayName}`,filterText:`${readModel.displayName} ${readModel.identifier}`,documentation:`Read model: ${readModel.displayName} (${readModel.identifier})`,detail:readModel.identifier,range:this.getRangeForWord(context)})}})}}addEventTypeCompletions(suggestions,context){Object.keys(this.eventSchemas).forEach(eventName=>{if(!context.currentWord||eventName.startsWith(context.currentWord)){let schema=this.eventSchemas[eventName];suggestions.push({label:eventName,kind:6,insertText:eventName,documentation:this.getSchemaDescription(schema)||`Event type: ${eventName}`,detail:"Event Type",range:this.getRangeForWord(context)})}})}addEventSequenceCompletions(suggestions,context){this.eventSequences.forEach(sequenceId=>{(!context.currentWord||sequenceId.startsWith(context.currentWord))&&suggestions.push({label:sequenceId,kind:13,insertText:sequenceId,documentation:`Event sequence: ${sequenceId}`,detail:"Event Sequence",range:this.getRangeForWord(context)})})}addKeyCompletions(suggestions,context,activeSchema){activeSchema?.definitions&&Object.keys(activeSchema.definitions).forEach(typeName=>{activeSchema.definitions[typeName].type==="object"&&suggestions.push({label:typeName,kind:6,insertText:typeName,documentation:`Composite key type: ${typeName}`,detail:"Composite Key Type",range:this.getRangeForWord(context)})}),this.addExpressionCompletions(suggestions,context)}addParentCompletions(suggestions,context){this.addExpressionCompletions(suggestions,context)}addNumericPropertyCompletions(suggestions,context,activeSchema){activeSchema?.properties&&Object.entries(activeSchema.properties).forEach(([propName,propSchema])=>{(propSchema.type==="integer"||propSchema.type==="number")&&(!context.currentWord||propName.startsWith(context.currentWord))&&suggestions.push({label:propName,kind:9,insertText:propName,documentation:`Numeric property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})});let addSubtractMatch=context.textBeforeCursor.match(/\b(add|subtract)\s+(\w*)$/);if(addSubtractMatch){let partialProp=addSubtractMatch[2]||"";activeSchema?.properties&&Object.entries(activeSchema.properties).forEach(([propName,propSchema])=>{(propSchema.type==="integer"||propSchema.type==="number")&&(!partialProp||propName.startsWith(partialProp))&&suggestions.push({label:propName,kind:9,insertText:`${propName} by `,documentation:`Numeric property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})})}}addChildrenCompletions(suggestions,context,activeSchema){activeSchema?.properties&&Object.entries(activeSchema.properties).forEach(([propName,propSchema])=>{(propSchema.type==="array"||propSchema.items)&&suggestions.push({label:propName,kind:9,insertText:`${propName} id `,documentation:`Collection property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})})}addJoinCompletions(suggestions,context,activeSchema){let trimmed=context.textBeforeCursor.trim();trimmed==="join"||!trimmed.includes(" ")?activeSchema?.properties&&Object.entries(activeSchema.properties).forEach(([propName,propSchema])=>{(propSchema.type==="array"||propSchema.items)&&suggestions.push({label:propName,kind:9,insertText:`${propName} on `,documentation:`Join on collection: ${propName}`,range:this.getRangeForWord(context)})}):trimmed.match(/join\s+\w+\s+on\s+/)&&activeSchema?.properties&&Object.keys(activeSchema.properties).forEach(propName=>{suggestions.push({label:propName,kind:9,insertText:propName,documentation:`Property: ${propName}`,range:this.getRangeForWord(context)})})}addVariantNameCompletions(suggestions,context){this.readModels.forEach(readModel=>{(!context.currentWord||readModel.displayName.toLowerCase().startsWith(context.currentWord.toLowerCase()))&&suggestions.push({label:readModel.displayName,kind:6,insertText:readModel.displayName,documentation:`Read model: ${readModel.displayName} (${readModel.identifier})`,detail:readModel.identifier,range:this.getRangeForWord(context)})})}addStatementCompletions(suggestions,context,activeSchema){[{label:"sequence",insertText:"sequence ",documentation:"Specify which event sequence to use for this projection",detail:"sequence <event-sequence-id>"},{label:"variant",insertText:"variant ",documentation:"Declare one of several mutually exclusive named read models sharing this projection's identity",detail:"variant <Name>"},{label:"enters on",insertText:"enters on ",documentation:"Declare the event that activates a variant",detail:"enters on <EventType>"},{label:"from",insertText:"from ",documentation:"Handle specific event types",detail:"from <EventType>"},{label:"all",insertText:"all",documentation:"Subscribe to all event types in the system \u2014 mappings run for every event system-wide, regardless of explicit from blocks",detail:"all"},{label:"every",insertText:"every",documentation:"Handle all events for automatic mapping (only events explicitly subscribed to via from blocks)",detail:"every"},{label:"key",insertText:"key ",documentation:"Define the projection key",detail:"key <expression>"},{label:"parent",insertText:"parent ",documentation:"Define parent relationship",detail:"parent <expression>"},{label:"join",insertText:"join ",documentation:"Join with child collection",detail:"join <collection> on <property>"},{label:"children",insertText:"children ",documentation:"Define child collection operations",detail:"children <collection> identified by <expression>"},{label:"remove with",insertText:"remove with ",documentation:"Remove items based on event",detail:"remove with <EventType>"},{label:"remove via",insertText:"remove via join on ",documentation:"Remove items via join",detail:"remove via join on <EventType>"},{label:"no automap",insertText:"no automap",documentation:"Disable automatic property mapping",detail:"no automap"},{label:"clear",insertText:"clear ",documentation:"Remove the value a property holds",detail:"clear <property>"},{label:"increment",insertText:"increment ",documentation:"Increment a numeric property",detail:"increment <property>"},{label:"decrement",insertText:"decrement ",documentation:"Decrement a numeric property",detail:"decrement <property>"},{label:"count",insertText:"count ",documentation:"Count occurrences",detail:"count <property>"},{label:"add",insertText:"add ",documentation:"Add value to property",detail:"add <property> by <expression>"},{label:"subtract",insertText:"subtract ",documentation:"Subtract value from property",detail:"subtract <property> by <expression>"},{label:"exclude children",insertText:"exclude children",documentation:"Exclude child collections from automap",detail:"exclude children"}].forEach(kw=>{(!context.currentWord||kw.label.startsWith(context.currentWord))&&suggestions.push({label:kw.label,kind:14,insertText:kw.insertText,documentation:kw.documentation,detail:kw.detail,range:this.getRangeForWord(context)})}),activeSchema?.properties&&Object.entries(activeSchema.properties).forEach(([propName,propSchema])=>{(!context.currentWord||propName.startsWith(context.currentWord))&&suggestions.push({label:propName,kind:9,insertText:`${propName} = `,documentation:`Assign value to property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})})}addAssignmentValueCompletions(suggestions,context,model,position){let eventType=this.getCurrentEventType(model,position.lineNumber);if(eventType&&this.eventSchemas[eventType]){let eventSchema=this.eventSchemas[eventType];eventSchema.properties&&Object.entries(eventSchema.properties).forEach(([propName,propSchema])=>{suggestions.push({label:propName,kind:9,insertText:propName,documentation:`Event property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})})}this.addExpressionCompletions(suggestions,context)}addExpressionCompletions(suggestions,context){[{label:"$eventSourceId",insertText:"$eventSourceId",documentation:"The identifier of the event source (aggregate/entity)",detail:"Event Source Expression"},{label:"$causedBy",insertText:"$causedBy",documentation:"The identity that caused the event. Chronicle cannot yet evaluate this short form (Cratis/Chronicle#4119) - prefer $eventContext.causedBy.<property>.",detail:"Identity Expression"},{label:"$eventContext",insertText:"$eventContext.",documentation:`Metadata about the event: ${eventContextMembers.map(member=>member.name).join(", ")}`,detail:"Event Context Expression"}].forEach(expr=>{(!context.currentWord||expr.label.startsWith(context.currentWord)||expr.label.startsWith("$"+context.currentWord))&&suggestions.push({label:expr.label,kind:14,insertText:expr.insertText,documentation:expr.documentation,detail:expr.detail,range:this.getRangeForWord(context)})})}addPropertyMemberCompletions(suggestions,context){let eventContextMatch=context.textBeforeCursor.match(EVENT_CONTEXT_PATH);if(eventContextMatch){let segments=eventContextMatch[1].split(".").filter(segment=>segment.length>0);this.addEventContextMemberCompletions(suggestions,context,segments,eventContextMatch[2]);return}let match=context.textBeforeCursor.match(/(\w+|\$\w+)\.(\w*)$/);if(!match)return;let[,objectName,partialProp]=match,causedByMatch=context.textBeforeCursor.match(/\$causedBy\.((?:\w+\.)*)(\w*)$/);if(causedByMatch){let segments=causedByMatch[1].split(".").filter(segment=>segment.length>0);this.addEventContextMemberCompletions(suggestions,context,["causedBy",...segments],causedByMatch[2]);return}let eventSchema=this.eventSchemas[objectName];eventSchema?.properties&&Object.entries(eventSchema.properties).forEach(([propName,propSchema])=>{(!partialProp||propName.startsWith(partialProp))&&suggestions.push({label:propName,kind:9,insertText:propName,documentation:`Event property: ${propName}`,detail:this.getPropertyTypeDescription(propSchema),range:this.getRangeForWord(context)})})}addEventContextMemberCompletions(suggestions,context,segments,partial){(eventContextMembersAfter(segments)??[]).filter(member=>!partial||member.name.startsWith(partial)).forEach(member=>{suggestions.push({label:member.name,kind:member.kind==="function"?1:9,insertText:member.name,documentation:member.description,detail:member.type,range:this.getRangeForWord(context)})})}getCurrentEventType(model,lineNumber){for(let i=lineNumber;i>=1;i--){let line=model.getLineContent(i).trim(),fromMatch=line.match(/^from\s+([\w-]+)/);if(fromMatch)return fromMatch[1];if(line.match(/^every$/))return null}return null}getActiveReadModelSchema(model){let match=model.getLineContent(1).trim().match(/^projection\s+[\w.]+\s*=>\s*([\w.]+)/);if(!match)return;let readModelName=match[1];return this.resolveReadModelInfo(readModelName)?.schema}resolveReadModelInfo(readModelToken){return this.readModels.find(rm=>rm.identifier===readModelToken||rm.displayName===readModelToken)||null}getSchemaName(schema){if(schema.name)return schema.name;if(schema.title)return schema.title;if(typeof schema.$id=="string"){let parts=schema.$id.split("/");return parts[parts.length-1]||schema.$id}}getSchemaDescription(schema){return schema.description||void 0}getPropertyTypeDescription(propSchema){return propSchema.type==="array"&&propSchema.items?`${propSchema.items.type||propSchema.items.$id?.split("/").pop()||"unknown"}[]`:propSchema.type||propSchema.$ref?.split("/").pop()||"unknown"}getRangeForWord(context){let startColumn=context.textBeforeCursor.length-context.currentWord.length+1,endColumn=startColumn+context.currentWord.length;return{startLineNumber:context.lineNumber,startColumn:Math.max(1,startColumn),endLineNumber:context.lineNumber,endColumn:Math.max(1,endColumn)}}};var Validator=class{readModels=[];eventSchemas={};draftReadModel=null;setReadModels(readModels){this.readModels=readModels||[]}setDraftReadModel(draft){this.draftReadModel=draft}setReadModelSchemas(schemas){this.readModels=schemas.map(schema=>({identifier:this.getSchemaName(schema)||"",displayName:this.getSchemaName(schema)||"",schema}))}setEventSchemas(schemas){if(!schemas){this.eventSchemas={};return}if(Array.isArray(schemas)){let map={};schemas.forEach((s,i)=>{if(!s)return;let name=this.getSchemaName(s)||`Event${i+1}`;map[name]=s}),this.eventSchemas=map;return}this.eventSchemas=schemas}validate(model){let markers=[],content=model.getValue();if(!content.trim())return markers;let lines=content.replace(/\r\n/g,`
2
+ `).replace(/\r/g,`
3
+ `).split(`
4
+ `),firstNonEmptyLineIndex=0,firstLine="";for(let i=0;i<lines.length;i++){let trimmed=lines[i].trim();if(trimmed&&!trimmed.startsWith("#")){firstNonEmptyLineIndex=i,firstLine=trimmed;break}}if(!firstLine)return markers;let projectionWithReadModelMatch=firstLine.match(/^projection\s+([\w.]+)\s*=>\s*([\w.]+)\s*$/),projectionAdHocMatch=!projectionWithReadModelMatch&&firstLine.match(/^projection\s+([\w.]+)\s*$/);if(!projectionWithReadModelMatch&&!projectionAdHocMatch){let lineNumber=firstNonEmptyLineIndex+1;return markers.push(this.createError(lineNumber,1,firstLine.length+1,'Projection definition must start with "projection <ProjectionName>" or "projection <ProjectionName> => <ReadModelIdentifier>"')),markers}let activeSchema,readModelName=null;if(projectionWithReadModelMatch){readModelName=projectionWithReadModelMatch[2];let readModelExists=this.resolveReadModelIdentifier(readModelName)!==null,isDraftReadModel=this.isDraftReadModel(readModelName),readModelStartColumn=this.getReadModelStartColumn(firstLine,readModelName);if(!readModelExists&&!isDraftReadModel){let lineNumber=firstNonEmptyLineIndex+1,col=readModelStartColumn;markers.push(this.createError(lineNumber,col,col+readModelName.length,`Read model '${readModelName}' not found`))}else if(isDraftReadModel){let lineNumber=firstNonEmptyLineIndex+1,col=readModelStartColumn;markers.push(this.createInfo(lineNumber,col,col+readModelName.length,`Read model '${readModelName}' is a draft (not yet saved)`))}let isDraft=this.isDraftReadModel(readModelName),activeReadModel=isDraft?null:this.resolveReadModelInfo(readModelName);activeSchema=isDraft?this.draftReadModel.schema:activeReadModel?.schema}let contextStack=[activeSchema],indentStack=[0],lastIndent=0,eventContextStack=[new Map];for(let i=1;i<lines.length;i++){let lineNumber=i+1,line=lines[i],trimmed=line.trim();if(!trimmed||trimmed.startsWith("#"))continue;let currentIndent=line.search(/\S/);for(;currentIndent<lastIndent&&indentStack.length>1;){let poppedIndent=indentStack.pop();poppedIndent!==void 0&&currentIndent<poppedIndent&&(contextStack.pop(),eventContextStack.pop())}lastIndent=currentIndent;let currentEventContext=eventContextStack[eventContextStack.length-1],fromMatch=trimmed.match(/^from\s+([\w-]+)/);if(fromMatch){let eventType=fromMatch[1],col=line.indexOf(eventType)+1;Object.keys(this.eventSchemas).length>0&&!this.eventSchemas[eventType]&&markers.push(this.createError(lineNumber,col,col+eventType.length,`Event type '${eventType}' not found`)),currentEventContext.has(eventType)?markers.push(this.createError(lineNumber,col,col+eventType.length,`Duplicate event type '${eventType}' - event types can only be used once at each level`)):currentEventContext.set(eventType,{lineNumber,col})}let variantMatch=trimmed.match(/^variant\s+([\w.]+)\s*$/);if(variantMatch){let[,variantName]=variantMatch,col=line.indexOf(variantName)+1,isDraft=this.isDraftReadModel(variantName);!(this.resolveReadModelIdentifier(variantName)!==null)&&!isDraft?markers.push(this.createError(lineNumber,col,col+variantName.length,`Read model '${variantName}' not found`)):isDraft&&markers.push(this.createInfo(lineNumber,col,col+variantName.length,`Read model '${variantName}' is a draft (not yet saved)`));let variantSchema=isDraft?this.draftReadModel.schema:this.resolveReadModelInfo(variantName)?.schema;contextStack.push(variantSchema),indentStack.push(currentIndent),eventContextStack.push(new Map)}let entersOnMatch=trimmed.match(/^enters\s+on\s+([\w-]+)/);if(entersOnMatch){let eventType=entersOnMatch[1],col=line.indexOf(eventType)+1;Object.keys(this.eventSchemas).length>0&&!this.eventSchemas[eventType]&&markers.push(this.createError(lineNumber,col,col+eventType.length,`Event type '${eventType}' not found`)),currentEventContext.has(eventType)?markers.push(this.createError(lineNumber,col,col+eventType.length,`Duplicate event type '${eventType}' - event types can only be used once at each level`)):currentEventContext.set(eventType,{lineNumber,col})}let eventsMatch=trimmed.match(/^events\s+([\w-]+)/);if(eventsMatch){let eventType=eventsMatch[1],col=line.indexOf(eventType)+1;Object.keys(this.eventSchemas).length>0&&!this.eventSchemas[eventType]&&markers.push(this.createError(lineNumber,col,col+eventType.length,`Event type '${eventType}' not found`)),currentEventContext.has(eventType)?markers.push(this.createError(lineNumber,col,col+eventType.length,`Duplicate event type '${eventType}' - event types can only be used once at each level`)):currentEventContext.set(eventType,{lineNumber,col})}let removeWithMatch=trimmed.match(/^remove\s+(?:with|via\s+join\s+on)\s+([\w-]+)/);if(removeWithMatch){let eventType=removeWithMatch[1],col=line.indexOf(eventType)+1;Object.keys(this.eventSchemas).length>0&&!this.eventSchemas[eventType]&&markers.push(this.createError(lineNumber,col,col+eventType.length,`Event type '${eventType}' not found`)),currentEventContext.has(eventType)?markers.push(this.createError(lineNumber,col,col+eventType.length,`Duplicate event type '${eventType}' - event types can only be used once at each level`)):currentEventContext.set(eventType,{lineNumber,col})}let assignmentMatch=trimmed.match(/^(\w+)\s*=\s*(.+)$/);if(assignmentMatch){let currentSchema=contextStack[contextStack.length-1];if(currentSchema?.properties){let[,propertyName]=assignmentMatch;if(!currentSchema.properties[propertyName]){let col=line.indexOf(propertyName)+1,schemaName=this.getSchemaName(currentSchema)||"current schema";markers.push(this.createWarning(lineNumber,col,col+propertyName.length,`Property '${propertyName}' not found in ${schemaName}`))}}}let numericOpMatch=trimmed.match(/^(?:increment|decrement|count)\s+(\w+)$/);if(numericOpMatch){let currentSchema=contextStack[contextStack.length-1];if(currentSchema?.properties){let[,propertyName]=numericOpMatch;if(!currentSchema.properties[propertyName]){let col=line.indexOf(propertyName)+1,schemaName=this.getSchemaName(currentSchema)||"current schema";markers.push(this.createWarning(lineNumber,col,col+propertyName.length,`Property '${propertyName}' not found in ${schemaName}`))}}}let addSubMatch=trimmed.match(/^(?:add|subtract)\s+(\w+)\s+by\s+/);if(addSubMatch){let currentSchema=contextStack[contextStack.length-1];if(currentSchema?.properties){let[,propertyName]=addSubMatch;if(!currentSchema.properties[propertyName]){let col=line.indexOf(propertyName)+1,schemaName=this.getSchemaName(currentSchema)||"current schema";markers.push(this.createWarning(lineNumber,col,col+propertyName.length,`Property '${propertyName}' not found in ${schemaName}`))}}}let childrenMatch=trimmed.match(/^children\s+(\w+)\s+identified\s+by\s+/);if(childrenMatch){let currentSchema=contextStack[contextStack.length-1];if(currentSchema?.properties){let[,propertyName]=childrenMatch,prop=currentSchema.properties[propertyName];if(prop)if(prop.type!=="array"&&!prop.items){let col=line.indexOf(propertyName)+1;markers.push(this.createWarning(lineNumber,col,col+propertyName.length,`Property '${propertyName}' is not a collection (array) type`))}else{let childSchema=prop.items;childSchema&&(contextStack.push(childSchema),indentStack.push(currentIndent),eventContextStack.push(new Map))}else{let col=line.indexOf(propertyName)+1,schemaName=this.getSchemaName(currentSchema)||"current schema";markers.push(this.createWarning(lineNumber,col,col+propertyName.length,`Collection property '${propertyName}' not found in ${schemaName}`))}}}let joinMatch=trimmed.match(/^join\s+(\w+)\s+on\s+(\w+)/);if(joinMatch&&activeSchema?.properties){let[,collectionName,joinProperty]=joinMatch,collectionProp=activeSchema.properties[collectionName];if(collectionProp){if(collectionProp.type!=="array"&&!collectionProp.items){let col=line.indexOf(collectionName)+1;markers.push(this.createWarning(lineNumber,col,col+collectionName.length,`Property '${collectionName}' is not a collection (array) type`))}}else{let col=line.indexOf(collectionName)+1;markers.push(this.createWarning(lineNumber,col,col+collectionName.length,`Collection property '${collectionName}' not found in read model '${readModelName}'`))}if(!activeSchema.properties[joinProperty]){let col=line.indexOf(joinProperty,line.indexOf("on"))+1;markers.push(this.createWarning(lineNumber,col,col+joinProperty.length,`Property '${joinProperty}' not found in read model '${readModelName}'`))}eventContextStack.push(new Map),indentStack.push(currentIndent)}let keyMatch=trimmed.match(/^key\s+(\w+)\s*$/);if(keyMatch&&activeSchema){let[,keyName]=keyMatch,isInDefinitions=activeSchema.definitions&&activeSchema.definitions[keyName],isProperty=activeSchema.properties&&activeSchema.properties[keyName];if(!isInDefinitions&&!isProperty&&!this.isBuiltInExpression(keyName)){let col=line.indexOf(keyName)+1;markers.push(this.createWarning(lineNumber,col,col+keyName.length,`Composite key type '${keyName}' not found in read model schema`))}}}for(let issue of validateEventContextPaths(lines,fenceMap(lines)))markers.push({severity:issue.severity==="error"?8:4,startLineNumber:issue.line+1,endLineNumber:issue.line+1,startColumn:issue.startColumn,endColumn:issue.endColumn,message:issue.message,code:issue.code});return markers}resolveReadModelInfo(readModelToken){return this.readModels.find(rm=>rm.identifier===readModelToken||rm.displayName===readModelToken)||null}getReadModelStartColumn(firstLine,readModelName){let prefixMatch=firstLine.match(/^\s*projection\s+[\w.]+\s*=>\s*/);if(!prefixMatch){let fallbackIndex=firstLine.lastIndexOf(readModelName);return(fallbackIndex>=0?fallbackIndex:0)+1}return prefixMatch[0].length+1}resolveReadModelIdentifier(readModelToken){return this.isDraftReadModel(readModelToken)?this.draftReadModel.identifier:this.resolveReadModelInfo(readModelToken)?.identifier??null}isDraftReadModel(readModelToken){return!!this.draftReadModel&&(this.draftReadModel.identifier===readModelToken||this.draftReadModel.displayName===readModelToken)}isBuiltInExpression(text){return text.startsWith("$")||["true","false","null"].includes(text)}createError(line,startCol,endCol,message){return{severity:8,startLineNumber:line,startColumn:startCol,endLineNumber:line,endColumn:endCol,message}}createWarning(line,startCol,endCol,message){return{severity:4,startLineNumber:line,startColumn:startCol,endLineNumber:line,endColumn:endCol,message}}createInfo(line,startCol,endCol,message){return{severity:2,startLineNumber:line,startColumn:startCol,endLineNumber:line,endColumn:endCol,message}}getSchemaName(schema){if(schema.name)return schema.name;if(schema.title)return schema.title;if(typeof schema.$id=="string"){let parts=schema.$id.split("/");return parts[parts.length-1]||schema.$id}}};var HoverProvider=class{readModels=[];eventSchemas={};draftReadModel=null;setReadModels(readModels){this.readModels=readModels||[]}setReadModelSchemas(schemas){this.readModels=schemas.map(schema=>({identifier:this.getSchemaName(schema)||"",displayName:this.getSchemaName(schema)||"",schema}))}setEventSchemas(schemas){if(!schemas){this.eventSchemas={};return}if(Array.isArray(schemas)){let map={};schemas.forEach((s,i)=>{if(!s)return;let name=this.getSchemaName(s)||`Event${i+1}`;map[name]=s}),this.eventSchemas=map;return}this.eventSchemas=schemas}setDraftReadModel(draft){this.draftReadModel=draft}provideHover(model,position){let word=model.getWordAtPosition(position);if(!word)return null;let wordText=word.word,lineContent=model.getLineContent(position.lineNumber);if(this.getProjectionNameAtPosition(lineContent,position.column))return{contents:[{value:"The name of the projection"}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}};let eventContextInfo=this.getEventContextInfo(lineContent,word.startColumn);if(eventContextInfo)return{contents:[{value:eventContextInfo}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}};let keywordInfo=this.getKeywordInfo(wordText);if(keywordInfo)return{contents:[{value:keywordInfo}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}};let expressionInfo=this.getExpressionInfo(wordText);if(expressionInfo)return{contents:[{value:expressionInfo}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}};if(this.eventSchemas[wordText]){let schema=this.eventSchemas[wordText],description=this.getSchemaDescription(schema),properties=this.getSchemaProperties(schema),content=`**Event Type:** \`${wordText}\`
10
5
 
11
- // sub-languages/projection/language.ts
12
- var languageId = "pdl";
13
- var KEYWORDS = [
14
- "projection",
15
- "sequence",
16
- "all",
17
- "every",
18
- "on",
19
- "from",
20
- "key",
21
- "parent",
22
- "join",
23
- "automap",
24
- "no",
25
- "children",
26
- "nested",
27
- "identified",
28
- "by",
29
- "add",
30
- "subtract",
31
- "remove",
32
- "via",
33
- "with",
34
- "default",
35
- "increment",
36
- "decrement",
37
- "count",
38
- "set",
39
- "unset",
40
- "clear",
41
- "events",
42
- "id",
43
- "exclude",
44
- "variant",
45
- "enters"
46
- ];
47
- var BUILTINS = [
48
- "$eventSourceId",
49
- "$causedBy",
50
- "$eventContext"
51
- ];
52
- var OPERATORS = ["=", "+=", "-=", "=>", "."];
53
- var configuration = {
54
- comments: {
55
- lineComment: "#"
56
- },
57
- brackets: [
58
- ["{", "}"],
59
- ["[", "]"],
60
- ["(", ")"]
61
- ],
62
- autoClosingPairs: [
63
- { open: "{", close: "}" },
64
- { open: "[", close: "]" },
65
- { open: "(", close: ")" },
66
- { open: '"', close: '"' },
67
- { open: "'", close: "'" },
68
- { open: "`", close: "`" }
69
- ],
70
- surroundingPairs: [
71
- { open: "{", close: "}" },
72
- { open: "[", close: "]" },
73
- { open: "(", close: ")" },
74
- { open: '"', close: '"' },
75
- { open: "'", close: "'" },
76
- { open: "`", close: "`" }
77
- ],
78
- indentationRules: {
79
- increaseIndentPattern: /^.*(:|\bon\b|\ball\b|\bevery\b|\bchildren\b|\bnested\b|\bparent\b|\bvariant\b)\s*$/,
80
- decreaseIndentPattern: /^.*\}.*$/
81
- },
82
- folding: {
83
- offSide: true,
84
- markers: {
85
- start: /^\s*(projection|all|every|on|children|nested|parent|variant)/,
86
- end: /^\s*$/
87
- }
88
- },
89
- wordPattern: /@?[a-zA-Z_$][\w$-]*/
90
- };
91
- var monarchLanguage = {
92
- defaultToken: "",
93
- tokenPostfix: ".pdl",
94
- keywords: KEYWORDS,
95
- builtins: BUILTINS,
96
- operators: OPERATORS,
97
- // Symbols
98
- symbols: /[=><!~?:&|+\-*/^%]+/,
99
- escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
100
- tokenizer: {
101
- root: [
102
- // Whitespace
103
- { include: "@whitespace" },
104
- // Template strings with ${...} interpolation
105
- [/`/, { token: "string.template", next: "@templateString" }],
106
- // Escaped identifiers (@ prefix allows using keywords as identifiers)
107
- [/@[a-zA-Z_$][\w$]*/, "identifier.escape"],
108
- // Check for uppercase keywords (error case - keywords must be lowercase)
109
- [
110
- /[A-Z][a-zA-Z_$][\w$]*/,
111
- {
112
- cases: {
113
- "@keywords": "invalid",
114
- "@default": "identifier"
115
- }
116
- }
117
- ],
118
- // Identifiers and keywords (lowercase only for keywords)
119
- [
120
- /[a-z_$][\w$]*/,
121
- {
122
- cases: {
123
- "@keywords": "keyword",
124
- "@builtins": "variable.predefined",
125
- "@default": "identifier"
126
- }
127
- }
128
- ],
129
- // Delimiters and operators
130
- [/[{}()[\]]/, "@brackets"],
131
- [/=>/, "operator.arrow"],
132
- [
133
- /@symbols/,
134
- {
135
- cases: {
136
- "@operators": "operator",
137
- "@default": ""
138
- }
139
- }
140
- ],
141
- // Numbers
142
- [/\d*\.\d+([eE][-+]?\d+)?/, "number.float"],
143
- [/0[xX][0-9a-fA-F]+/, "number.hex"],
144
- [/\d+/, "number"],
145
- // Delimiter: after number because of .\d floats
146
- [/[;,.]/, "delimiter"],
147
- // Strings
148
- [/"([^"\\]|\\.)*$/, "string.invalid"],
149
- [/"/, { token: "string.quote", next: "@string" }]
150
- ],
151
- whitespace: [
152
- [/[ \t\r\n]+/, ""],
153
- [/#.*$/, "comment"]
154
- ],
155
- // Template string state
156
- templateString: [
157
- [/\$\{/, { token: "delimiter.bracket", next: "@templateExpression" }],
158
- [/[^\\`$]+/, "string.template"],
159
- [/@escapes/, "string.template.escape"],
160
- [/\\./, "string.template.escape.invalid"],
161
- [/`/, { token: "string.template", next: "@pop" }]
162
- ],
163
- // Template expression inside ${}
164
- templateExpression: [
165
- [/\}/, { token: "delimiter.bracket", next: "@pop" }],
166
- { include: "@root" }
167
- ],
168
- // Regular string state
169
- string: [
170
- [/[^\\"]+/, "string"],
171
- [/@escapes/, "string.escape"],
172
- [/\\./, "string.escape.invalid"],
173
- [/"/, { token: "string.quote", next: "@pop" }]
174
- ]
175
- }
176
- };
6
+ `;return description&&(content+=`${description}
177
7
 
178
- // sub-languages/projection/CompletionProvider.ts
179
- var EVENT_CONTEXT_PATH = /\$eventContext\.((?:\w+\.)*)(\w*)$/;
180
- var CompletionProvider = class {
181
- readModels = [];
182
- eventSchemas = {};
183
- eventSequences = [];
184
- setReadModels(readModels) {
185
- this.readModels = readModels || [];
186
- }
187
- setEventSequences(sequences) {
188
- this.eventSequences = sequences || [];
189
- }
190
- // Keep for backwards compatibility
191
- setReadModelSchemas(schemas) {
192
- this.readModels = schemas.map((schema) => ({
193
- identifier: this.getSchemaName(schema) || "",
194
- displayName: this.getSchemaName(schema) || "",
195
- schema
196
- }));
197
- }
198
- setEventSchemas(schemas) {
199
- if (!schemas) {
200
- this.eventSchemas = {};
201
- return;
202
- }
203
- if (Array.isArray(schemas)) {
204
- const map = {};
205
- schemas.forEach((s, i) => {
206
- if (!s) return;
207
- const name = this.getSchemaName(s) || `Event${i + 1}`;
208
- map[name] = s;
209
- });
210
- this.eventSchemas = map;
211
- return;
212
- }
213
- this.eventSchemas = schemas;
214
- }
215
- provideCompletionItems(model, position) {
216
- const context = this.buildContext(model, position);
217
- const suggestions = [];
218
- const activeSchema = this.getActiveReadModelSchema(model);
219
- if (context.lineNumber === 1) {
220
- this.addProjectionLineCompletions(suggestions, context);
221
- } else if (this.isAfterKeyword(context, "sequence")) {
222
- this.addEventSequenceCompletions(suggestions, context);
223
- } else if (this.isAfterKeyword(context, "from") || this.isAfterKeyword(context, "every")) {
224
- this.addEventTypeCompletions(suggestions, context);
225
- } else if (/\benters\s+on\s+\w*$/.test(context.textBeforeCursor)) {
226
- this.addEventTypeCompletions(suggestions, context);
227
- } else if (/\benters\s+\w*$/.test(context.textBeforeCursor)) {
228
- suggestions.push({
229
- label: "on",
230
- kind: 14,
231
- // Keyword
232
- insertText: "on ",
233
- documentation: "Declares the event that activates this variant.",
234
- detail: "enters on <EventType>",
235
- range: this.getRangeForWord(context)
236
- });
237
- } else if (this.isAfterKeyword(context, "variant")) {
238
- this.addVariantNameCompletions(suggestions, context);
239
- } else if (this.isAfterKeyword(context, "key")) {
240
- this.addKeyCompletions(suggestions, context, activeSchema);
241
- } else if (this.isAfterKeyword(context, "parent")) {
242
- this.addParentCompletions(suggestions, context);
243
- } else if (this.isAfterKeyword(context, "children")) {
244
- this.addChildrenCompletions(suggestions, context, activeSchema);
245
- } else if (this.isAfterKeyword(context, "join")) {
246
- this.addJoinCompletions(suggestions, context, activeSchema);
247
- } else if (this.isAfterKeyword(context, "with")) {
248
- this.addEventTypeCompletions(suggestions, context);
249
- } else if (this.isAfterNumericOperationKeyword(context)) {
250
- this.addNumericPropertyCompletions(suggestions, context, activeSchema);
251
- } else if (this.isAfterAddOrSubtractBy(context)) {
252
- this.addAssignmentValueCompletions(suggestions, context, model, position);
253
- } else if (this.isInAssignment(context)) {
254
- this.addAssignmentValueCompletions(suggestions, context, model, position);
255
- } else if (this.isPropertyDotAccess(context)) {
256
- this.addPropertyMemberCompletions(suggestions, context);
257
- } else if (this.isStartOfLine(context) || this.isAfterIndent(context)) {
258
- this.addStatementCompletions(suggestions, context, activeSchema);
259
- }
260
- return { suggestions };
261
- }
262
- buildContext(model, position) {
263
- const lineContent = model.getLineContent(position.lineNumber);
264
- const textBeforeCursor = lineContent.substring(0, position.column - 1);
265
- const textAfterCursor = lineContent.substring(position.column - 1);
266
- const word = model.getWordAtPosition(position);
267
- const currentWord = word?.word || "";
268
- const indentLevel = this.getIndentLevel(textBeforeCursor);
269
- return {
270
- lineContent,
271
- textBeforeCursor,
272
- textAfterCursor,
273
- currentWord,
274
- indentLevel,
275
- lineNumber: position.lineNumber
276
- };
277
- }
278
- getIndentLevel(text) {
279
- const match = text.match(/^(\s*)/);
280
- return match ? Math.floor(match[1].length / 2) : 0;
281
- }
282
- isStartOfLine(context) {
283
- return context.textBeforeCursor.trim() === "";
284
- }
285
- isAfterIndent(context) {
286
- return /^\s+$/.test(context.textBeforeCursor);
287
- }
288
- isAfterKeyword(context, keyword) {
289
- const pattern = new RegExp(`\\b${keyword}\\s+\\w*$`);
290
- return pattern.test(context.textBeforeCursor);
291
- }
292
- isAfterNumericOperationKeyword(context) {
293
- const countIncrDecrPattern = /\b(count|increment|decrement)\s+\w*$/;
294
- const addSubtractPattern = /\b(add|subtract)\s+\w*$/;
295
- if (countIncrDecrPattern.test(context.textBeforeCursor)) {
296
- return true;
297
- }
298
- if (addSubtractPattern.test(context.textBeforeCursor)) {
299
- return !this.isAfterAddOrSubtractBy(context);
300
- }
301
- return false;
302
- }
303
- isAfterAddOrSubtractBy(context) {
304
- const pattern = /\b(add|subtract)\s+\w+\s+by\s+\w*$/;
305
- return pattern.test(context.textBeforeCursor);
306
- }
307
- isInAssignment(context) {
308
- return /\w+\s*=\s*\w*$/.test(context.textBeforeCursor);
309
- }
310
- isPropertyDotAccess(context) {
311
- return /(\w+|\$\w+)\.(\w*)$/.test(context.textBeforeCursor) || EVENT_CONTEXT_PATH.test(context.textBeforeCursor);
312
- }
313
- addProjectionLineCompletions(suggestions, context) {
314
- const trimmed = context.textBeforeCursor.trim();
315
- if (trimmed === "" || "projection".startsWith(trimmed)) {
316
- suggestions.push({
317
- label: "projection",
318
- kind: 14,
319
- // Keyword
320
- insertText: "projection ",
321
- documentation: "Define a projection that transforms events into a read model",
322
- detail: "projection <ProjectionName>",
323
- range: this.getRangeForWord(context)
324
- });
325
- }
326
- const arrowMatch = trimmed.match(/^projection\s+[\w.]+\s*=>\s*([\w.]*)$/);
327
- if (arrowMatch) {
328
- const partialReadModel = arrowMatch[1] || "";
329
- this.readModels.forEach((readModel) => {
330
- if (!partialReadModel || readModel.displayName.toLowerCase().startsWith(partialReadModel.toLowerCase())) {
331
- const label = `${readModel.displayName} (${readModel.identifier})`;
332
- suggestions.push({
333
- label,
334
- kind: 6,
335
- // Class
336
- insertText: readModel.displayName,
337
- filterText: `${readModel.displayName} ${readModel.identifier}`,
338
- documentation: `Read model: ${readModel.displayName} (${readModel.identifier})`,
339
- detail: readModel.identifier,
340
- range: this.getRangeForWord(context)
341
- });
342
- }
343
- });
344
- return;
345
- }
346
- if (trimmed.startsWith("projection ") && !trimmed.includes("=>")) {
347
- const afterProjection = trimmed.substring("projection ".length);
348
- this.readModels.forEach((readModel) => {
349
- if (!afterProjection || readModel.displayName.toLowerCase().startsWith(afterProjection.toLowerCase())) {
350
- const label = `${readModel.displayName} (${readModel.identifier})`;
351
- suggestions.push({
352
- label,
353
- kind: 6,
354
- // Class
355
- insertText: `${readModel.displayName} => ${readModel.displayName}`,
356
- filterText: `${readModel.displayName} ${readModel.identifier}`,
357
- documentation: `Read model: ${readModel.displayName} (${readModel.identifier})`,
358
- detail: readModel.identifier,
359
- range: this.getRangeForWord(context)
360
- });
361
- }
362
- });
363
- }
364
- }
365
- addEventTypeCompletions(suggestions, context) {
366
- Object.keys(this.eventSchemas).forEach((eventName) => {
367
- if (!context.currentWord || eventName.startsWith(context.currentWord)) {
368
- const schema = this.eventSchemas[eventName];
369
- suggestions.push({
370
- label: eventName,
371
- kind: 6,
372
- // Class
373
- insertText: eventName,
374
- documentation: this.getSchemaDescription(schema) || `Event type: ${eventName}`,
375
- detail: "Event Type",
376
- range: this.getRangeForWord(context)
377
- });
378
- }
379
- });
380
- }
381
- addEventSequenceCompletions(suggestions, context) {
382
- this.eventSequences.forEach((sequenceId) => {
383
- if (!context.currentWord || sequenceId.startsWith(context.currentWord)) {
384
- suggestions.push({
385
- label: sequenceId,
386
- kind: 13,
387
- // Value
388
- insertText: sequenceId,
389
- documentation: `Event sequence: ${sequenceId}`,
390
- detail: "Event Sequence",
391
- range: this.getRangeForWord(context)
392
- });
393
- }
394
- });
395
- }
396
- addKeyCompletions(suggestions, context, activeSchema) {
397
- if (activeSchema?.definitions) {
398
- Object.keys(activeSchema.definitions).forEach((typeName) => {
399
- const typeDef = activeSchema.definitions[typeName];
400
- if (typeDef.type === "object") {
401
- suggestions.push({
402
- label: typeName,
403
- kind: 6,
404
- // Class
405
- insertText: typeName,
406
- documentation: `Composite key type: ${typeName}`,
407
- detail: "Composite Key Type",
408
- range: this.getRangeForWord(context)
409
- });
410
- }
411
- });
412
- }
413
- this.addExpressionCompletions(suggestions, context);
414
- }
415
- addParentCompletions(suggestions, context) {
416
- this.addExpressionCompletions(suggestions, context);
417
- }
418
- addNumericPropertyCompletions(suggestions, context, activeSchema) {
419
- if (activeSchema?.properties) {
420
- Object.entries(activeSchema.properties).forEach(([propName, propSchema]) => {
421
- const isNumeric = propSchema.type === "integer" || propSchema.type === "number";
422
- if (isNumeric) {
423
- if (!context.currentWord || propName.startsWith(context.currentWord)) {
424
- suggestions.push({
425
- label: propName,
426
- kind: 9,
427
- // Property
428
- insertText: propName,
429
- documentation: `Numeric property: ${propName}`,
430
- detail: this.getPropertyTypeDescription(propSchema),
431
- range: this.getRangeForWord(context)
432
- });
433
- }
434
- }
435
- });
436
- }
437
- const addSubtractMatch = context.textBeforeCursor.match(/\b(add|subtract)\s+(\w*)$/);
438
- if (addSubtractMatch) {
439
- const partialProp = addSubtractMatch[2] || "";
440
- if (activeSchema?.properties) {
441
- Object.entries(activeSchema.properties).forEach(([propName, propSchema]) => {
442
- const isNumeric = propSchema.type === "integer" || propSchema.type === "number";
443
- if (isNumeric && (!partialProp || propName.startsWith(partialProp))) {
444
- suggestions.push({
445
- label: propName,
446
- kind: 9,
447
- // Property
448
- insertText: `${propName} by `,
449
- documentation: `Numeric property: ${propName}`,
450
- detail: this.getPropertyTypeDescription(propSchema),
451
- range: this.getRangeForWord(context)
452
- });
453
- }
454
- });
455
- }
456
- }
457
- }
458
- addChildrenCompletions(suggestions, context, activeSchema) {
459
- if (activeSchema?.properties) {
460
- Object.entries(activeSchema.properties).forEach(([propName, propSchema]) => {
461
- if (propSchema.type === "array" || propSchema.items) {
462
- suggestions.push({
463
- label: propName,
464
- kind: 9,
465
- // Property
466
- insertText: `${propName} id `,
467
- documentation: `Collection property: ${propName}`,
468
- detail: this.getPropertyTypeDescription(propSchema),
469
- range: this.getRangeForWord(context)
470
- });
471
- }
472
- });
473
- }
474
- }
475
- addJoinCompletions(suggestions, context, activeSchema) {
476
- const trimmed = context.textBeforeCursor.trim();
477
- if (trimmed === "join" || !trimmed.includes(" ")) {
478
- if (activeSchema?.properties) {
479
- Object.entries(activeSchema.properties).forEach(([propName, propSchema]) => {
480
- if (propSchema.type === "array" || propSchema.items) {
481
- suggestions.push({
482
- label: propName,
483
- kind: 9,
484
- insertText: `${propName} on `,
485
- documentation: `Join on collection: ${propName}`,
486
- range: this.getRangeForWord(context)
487
- });
488
- }
489
- });
490
- }
491
- } else if (trimmed.match(/join\s+\w+\s+on\s+/)) {
492
- if (activeSchema?.properties) {
493
- Object.keys(activeSchema.properties).forEach((propName) => {
494
- suggestions.push({
495
- label: propName,
496
- kind: 9,
497
- insertText: propName,
498
- documentation: `Property: ${propName}`,
499
- range: this.getRangeForWord(context)
500
- });
501
- });
502
- }
503
- }
504
- }
505
- addVariantNameCompletions(suggestions, context) {
506
- this.readModels.forEach((readModel) => {
507
- if (!context.currentWord || readModel.displayName.toLowerCase().startsWith(context.currentWord.toLowerCase())) {
508
- suggestions.push({
509
- label: readModel.displayName,
510
- kind: 6,
511
- // Class
512
- insertText: readModel.displayName,
513
- documentation: `Read model: ${readModel.displayName} (${readModel.identifier})`,
514
- detail: readModel.identifier,
515
- range: this.getRangeForWord(context)
516
- });
517
- }
518
- });
519
- }
520
- addStatementCompletions(suggestions, context, activeSchema) {
521
- const keywords = [
522
- { label: "sequence", insertText: "sequence ", documentation: "Specify which event sequence to use for this projection", detail: "sequence <event-sequence-id>" },
523
- { label: "variant", insertText: "variant ", documentation: "Declare one of several mutually exclusive named read models sharing this projection's identity", detail: "variant <Name>" },
524
- { label: "enters on", insertText: "enters on ", documentation: "Declare the event that activates a variant", detail: "enters on <EventType>" },
525
- { label: "from", insertText: "from ", documentation: "Handle specific event types", detail: "from <EventType>" },
526
- { label: "all", insertText: "all", documentation: "Subscribe to all event types in the system \u2014 mappings run for every event system-wide, regardless of explicit from blocks", detail: "all" },
527
- { label: "every", insertText: "every", documentation: "Handle all events for automatic mapping (only events explicitly subscribed to via from blocks)", detail: "every" },
528
- { label: "key", insertText: "key ", documentation: "Define the projection key", detail: "key <expression>" },
529
- { label: "parent", insertText: "parent ", documentation: "Define parent relationship", detail: "parent <expression>" },
530
- { label: "join", insertText: "join ", documentation: "Join with child collection", detail: "join <collection> on <property>" },
531
- { label: "children", insertText: "children ", documentation: "Define child collection operations", detail: "children <collection> identified by <expression>" },
532
- { label: "remove with", insertText: "remove with ", documentation: "Remove items based on event", detail: "remove with <EventType>" },
533
- { label: "remove via", insertText: "remove via join on ", documentation: "Remove items via join", detail: "remove via join on <EventType>" },
534
- { label: "no automap", insertText: "no automap", documentation: "Disable automatic property mapping", detail: "no automap" },
535
- { label: "clear", insertText: "clear ", documentation: "Remove the value a property holds", detail: "clear <property>" },
536
- { label: "increment", insertText: "increment ", documentation: "Increment a numeric property", detail: "increment <property>" },
537
- { label: "decrement", insertText: "decrement ", documentation: "Decrement a numeric property", detail: "decrement <property>" },
538
- { label: "count", insertText: "count ", documentation: "Count occurrences", detail: "count <property>" },
539
- { label: "add", insertText: "add ", documentation: "Add value to property", detail: "add <property> by <expression>" },
540
- { label: "subtract", insertText: "subtract ", documentation: "Subtract value from property", detail: "subtract <property> by <expression>" },
541
- { label: "exclude children", insertText: "exclude children", documentation: "Exclude child collections from automap", detail: "exclude children" }
542
- ];
543
- keywords.forEach((kw) => {
544
- if (!context.currentWord || kw.label.startsWith(context.currentWord)) {
545
- suggestions.push({
546
- label: kw.label,
547
- kind: 14,
548
- // Keyword
549
- insertText: kw.insertText,
550
- documentation: kw.documentation,
551
- detail: kw.detail,
552
- range: this.getRangeForWord(context)
553
- });
554
- }
555
- });
556
- if (activeSchema?.properties) {
557
- Object.entries(activeSchema.properties).forEach(([propName, propSchema]) => {
558
- if (!context.currentWord || propName.startsWith(context.currentWord)) {
559
- suggestions.push({
560
- label: propName,
561
- kind: 9,
562
- // Property
563
- insertText: `${propName} = `,
564
- documentation: `Assign value to property: ${propName}`,
565
- detail: this.getPropertyTypeDescription(propSchema),
566
- range: this.getRangeForWord(context)
567
- });
568
- }
569
- });
570
- }
571
- }
572
- addAssignmentValueCompletions(suggestions, context, model, position) {
573
- const eventType = this.getCurrentEventType(model, position.lineNumber);
574
- if (eventType && this.eventSchemas[eventType]) {
575
- const eventSchema = this.eventSchemas[eventType];
576
- if (eventSchema.properties) {
577
- Object.entries(eventSchema.properties).forEach(([propName, propSchema]) => {
578
- suggestions.push({
579
- label: propName,
580
- kind: 9,
581
- insertText: propName,
582
- documentation: `Event property: ${propName}`,
583
- detail: this.getPropertyTypeDescription(propSchema),
584
- range: this.getRangeForWord(context)
585
- });
586
- });
587
- }
588
- }
589
- this.addExpressionCompletions(suggestions, context);
590
- }
591
- addExpressionCompletions(suggestions, context) {
592
- const expressions = [
593
- {
594
- label: "$eventSourceId",
595
- insertText: "$eventSourceId",
596
- documentation: "The identifier of the event source (aggregate/entity)",
597
- detail: "Event Source Expression"
598
- },
599
- {
600
- label: "$causedBy",
601
- insertText: "$causedBy",
602
- documentation: "The identity that caused the event. Chronicle cannot yet evaluate this short form (Cratis/Chronicle#4119) - prefer $eventContext.causedBy.<property>.",
603
- detail: "Identity Expression"
604
- },
605
- {
606
- label: "$eventContext",
607
- insertText: "$eventContext.",
608
- documentation: `Metadata about the event: ${eventContextMembers.map((member) => member.name).join(", ")}`,
609
- detail: "Event Context Expression"
610
- }
611
- ];
612
- expressions.forEach((expr) => {
613
- if (!context.currentWord || expr.label.startsWith(context.currentWord) || expr.label.startsWith("$" + context.currentWord)) {
614
- suggestions.push({
615
- label: expr.label,
616
- kind: 14,
617
- // Keyword/builtin
618
- insertText: expr.insertText,
619
- documentation: expr.documentation,
620
- detail: expr.detail,
621
- range: this.getRangeForWord(context)
622
- });
623
- }
624
- });
625
- }
626
- addPropertyMemberCompletions(suggestions, context) {
627
- const eventContextMatch = context.textBeforeCursor.match(EVENT_CONTEXT_PATH);
628
- if (eventContextMatch) {
629
- const segments = eventContextMatch[1].split(".").filter((segment) => segment.length > 0);
630
- this.addEventContextMemberCompletions(suggestions, context, segments, eventContextMatch[2]);
631
- return;
632
- }
633
- const match = context.textBeforeCursor.match(/(\w+|\$\w+)\.(\w*)$/);
634
- if (!match) return;
635
- const [, objectName, partialProp] = match;
636
- const causedByMatch = context.textBeforeCursor.match(/\$causedBy\.((?:\w+\.)*)(\w*)$/);
637
- if (causedByMatch) {
638
- const segments = causedByMatch[1].split(".").filter((segment) => segment.length > 0);
639
- this.addEventContextMemberCompletions(suggestions, context, ["causedBy", ...segments], causedByMatch[2]);
640
- return;
641
- }
642
- const eventSchema = this.eventSchemas[objectName];
643
- if (eventSchema?.properties) {
644
- Object.entries(eventSchema.properties).forEach(([propName, propSchema]) => {
645
- if (!partialProp || propName.startsWith(partialProp)) {
646
- suggestions.push({
647
- label: propName,
648
- kind: 9,
649
- insertText: propName,
650
- documentation: `Event property: ${propName}`,
651
- detail: this.getPropertyTypeDescription(propSchema),
652
- range: this.getRangeForWord(context)
653
- });
654
- }
655
- });
656
- }
657
- }
658
- addEventContextMemberCompletions(suggestions, context, segments, partial) {
659
- const members = eventContextMembersAfter(segments) ?? [];
660
- members.filter((member) => !partial || member.name.startsWith(partial)).forEach((member) => {
661
- suggestions.push({
662
- label: member.name,
663
- kind: member.kind === "function" ? 1 : 9,
664
- insertText: member.name,
665
- documentation: member.description,
666
- detail: member.type,
667
- range: this.getRangeForWord(context)
668
- });
669
- });
670
- }
671
- getCurrentEventType(model, lineNumber) {
672
- for (let i = lineNumber; i >= 1; i--) {
673
- const line = model.getLineContent(i).trim();
674
- const fromMatch = line.match(/^from\s+([\w-]+)/);
675
- if (fromMatch) {
676
- return fromMatch[1];
677
- }
678
- const everyMatch = line.match(/^every$/);
679
- if (everyMatch) {
680
- return null;
681
- }
682
- }
683
- return null;
684
- }
685
- getActiveReadModelSchema(model) {
686
- const firstLine = model.getLineContent(1).trim();
687
- const match = firstLine.match(/^projection\s+[\w.]+\s*=>\s*([\w.]+)/);
688
- if (!match) return void 0;
689
- const readModelName = match[1];
690
- const readModel = this.resolveReadModelInfo(readModelName);
691
- return readModel?.schema;
692
- }
693
- resolveReadModelInfo(readModelToken) {
694
- return this.readModels.find((rm) => rm.identifier === readModelToken || rm.displayName === readModelToken) || null;
695
- }
696
- getSchemaName(schema) {
697
- if (schema.name) return schema.name;
698
- if (schema.title) return schema.title;
699
- if (typeof schema.$id === "string") {
700
- const parts = schema.$id.split("/");
701
- return parts[parts.length - 1] || schema.$id;
702
- }
703
- return void 0;
704
- }
705
- getSchemaDescription(schema) {
706
- return schema.description || void 0;
707
- }
708
- getPropertyTypeDescription(propSchema) {
709
- if (propSchema.type === "array" && propSchema.items) {
710
- const itemType = propSchema.items.type || propSchema.items.$id?.split("/").pop() || "unknown";
711
- return `${itemType}[]`;
712
- }
713
- return propSchema.type || propSchema.$ref?.split("/").pop() || "unknown";
714
- }
715
- getRangeForWord(context) {
716
- const startColumn = context.textBeforeCursor.length - context.currentWord.length + 1;
717
- const endColumn = startColumn + context.currentWord.length;
718
- return {
719
- startLineNumber: context.lineNumber,
720
- startColumn: Math.max(1, startColumn),
721
- endLineNumber: context.lineNumber,
722
- endColumn: Math.max(1, endColumn)
723
- };
724
- }
725
- };
8
+ `),properties.length>0&&(content+=`**Properties:**
726
9
 
727
- // sub-languages/projection/Validator.ts
728
- var Validator = class {
729
- readModels = [];
730
- eventSchemas = {};
731
- draftReadModel = null;
732
- setReadModels(readModels) {
733
- this.readModels = readModels || [];
734
- }
735
- setDraftReadModel(draft) {
736
- this.draftReadModel = draft;
737
- }
738
- // Keep for backwards compatibility
739
- setReadModelSchemas(schemas) {
740
- this.readModels = schemas.map((schema) => ({
741
- identifier: this.getSchemaName(schema) || "",
742
- displayName: this.getSchemaName(schema) || "",
743
- schema
744
- }));
745
- }
746
- setEventSchemas(schemas) {
747
- if (!schemas) {
748
- this.eventSchemas = {};
749
- return;
750
- }
751
- if (Array.isArray(schemas)) {
752
- const map = {};
753
- schemas.forEach((s, i) => {
754
- if (!s) return;
755
- const name = this.getSchemaName(s) || `Event${i + 1}`;
756
- map[name] = s;
757
- });
758
- this.eventSchemas = map;
759
- return;
760
- }
761
- this.eventSchemas = schemas;
762
- }
763
- validate(model) {
764
- const markers = [];
765
- const content = model.getValue();
766
- if (!content.trim()) {
767
- return markers;
768
- }
769
- const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
770
- let firstNonEmptyLineIndex = 0;
771
- let firstLine = "";
772
- for (let i = 0; i < lines.length; i++) {
773
- const trimmed = lines[i].trim();
774
- if (trimmed && !trimmed.startsWith("#")) {
775
- firstNonEmptyLineIndex = i;
776
- firstLine = trimmed;
777
- break;
778
- }
779
- }
780
- if (!firstLine) {
781
- return markers;
782
- }
783
- const projectionWithReadModelMatch = firstLine.match(/^projection\s+([\w.]+)\s*=>\s*([\w.]+)\s*$/);
784
- const projectionAdHocMatch = !projectionWithReadModelMatch && firstLine.match(/^projection\s+([\w.]+)\s*$/);
785
- if (!projectionWithReadModelMatch && !projectionAdHocMatch) {
786
- const lineNumber = firstNonEmptyLineIndex + 1;
787
- markers.push(this.createError(lineNumber, 1, firstLine.length + 1, 'Projection definition must start with "projection <ProjectionName>" or "projection <ProjectionName> => <ReadModelIdentifier>"'));
788
- return markers;
789
- }
790
- let activeSchema;
791
- let readModelName = null;
792
- if (projectionWithReadModelMatch) {
793
- readModelName = projectionWithReadModelMatch[2];
794
- const readModelExists = this.resolveReadModelIdentifier(readModelName) !== null;
795
- const isDraftReadModel = this.isDraftReadModel(readModelName);
796
- const readModelStartColumn = this.getReadModelStartColumn(firstLine, readModelName);
797
- if (!readModelExists && !isDraftReadModel) {
798
- const lineNumber = firstNonEmptyLineIndex + 1;
799
- const col = readModelStartColumn;
800
- markers.push(this.createError(lineNumber, col, col + readModelName.length, `Read model '${readModelName}' not found`));
801
- } else if (isDraftReadModel) {
802
- const lineNumber = firstNonEmptyLineIndex + 1;
803
- const col = readModelStartColumn;
804
- markers.push(this.createInfo(lineNumber, col, col + readModelName.length, `Read model '${readModelName}' is a draft (not yet saved)`));
805
- }
806
- const isDraft = this.isDraftReadModel(readModelName);
807
- const activeReadModel = isDraft ? null : this.resolveReadModelInfo(readModelName);
808
- activeSchema = isDraft ? this.draftReadModel.schema : activeReadModel?.schema;
809
- }
810
- const contextStack = [activeSchema];
811
- const indentStack = [0];
812
- let lastIndent = 0;
813
- const eventContextStack = [/* @__PURE__ */ new Map()];
814
- for (let i = 1; i < lines.length; i++) {
815
- const lineNumber = i + 1;
816
- const line = lines[i];
817
- const trimmed = line.trim();
818
- if (!trimmed || trimmed.startsWith("#")) continue;
819
- const currentIndent = line.search(/\S/);
820
- while (currentIndent < lastIndent && indentStack.length > 1) {
821
- const poppedIndent = indentStack.pop();
822
- if (poppedIndent !== void 0 && currentIndent < poppedIndent) {
823
- contextStack.pop();
824
- eventContextStack.pop();
825
- }
826
- }
827
- lastIndent = currentIndent;
828
- const currentEventContext = eventContextStack[eventContextStack.length - 1];
829
- const fromMatch = trimmed.match(/^from\s+([\w-]+)/);
830
- if (fromMatch) {
831
- const eventType = fromMatch[1];
832
- const col = line.indexOf(eventType) + 1;
833
- if (Object.keys(this.eventSchemas).length > 0 && !this.eventSchemas[eventType]) {
834
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Event type '${eventType}' not found`));
835
- }
836
- if (currentEventContext.has(eventType)) {
837
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Duplicate event type '${eventType}' - event types can only be used once at each level`));
838
- } else {
839
- currentEventContext.set(eventType, { lineNumber, col });
840
- }
841
- }
842
- const variantMatch = trimmed.match(/^variant\s+([\w.]+)\s*$/);
843
- if (variantMatch) {
844
- const [, variantName] = variantMatch;
845
- const col = line.indexOf(variantName) + 1;
846
- const isDraft = this.isDraftReadModel(variantName);
847
- const readModelExists = this.resolveReadModelIdentifier(variantName) !== null;
848
- if (!readModelExists && !isDraft) {
849
- markers.push(this.createError(lineNumber, col, col + variantName.length, `Read model '${variantName}' not found`));
850
- } else if (isDraft) {
851
- markers.push(this.createInfo(lineNumber, col, col + variantName.length, `Read model '${variantName}' is a draft (not yet saved)`));
852
- }
853
- const variantSchema = isDraft ? this.draftReadModel.schema : this.resolveReadModelInfo(variantName)?.schema;
854
- contextStack.push(variantSchema);
855
- indentStack.push(currentIndent);
856
- eventContextStack.push(/* @__PURE__ */ new Map());
857
- }
858
- const entersOnMatch = trimmed.match(/^enters\s+on\s+([\w-]+)/);
859
- if (entersOnMatch) {
860
- const eventType = entersOnMatch[1];
861
- const col = line.indexOf(eventType) + 1;
862
- if (Object.keys(this.eventSchemas).length > 0 && !this.eventSchemas[eventType]) {
863
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Event type '${eventType}' not found`));
864
- }
865
- if (currentEventContext.has(eventType)) {
866
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Duplicate event type '${eventType}' - event types can only be used once at each level`));
867
- } else {
868
- currentEventContext.set(eventType, { lineNumber, col });
869
- }
870
- }
871
- const eventsMatch = trimmed.match(/^events\s+([\w-]+)/);
872
- if (eventsMatch) {
873
- const eventType = eventsMatch[1];
874
- const col = line.indexOf(eventType) + 1;
875
- if (Object.keys(this.eventSchemas).length > 0 && !this.eventSchemas[eventType]) {
876
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Event type '${eventType}' not found`));
877
- }
878
- if (currentEventContext.has(eventType)) {
879
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Duplicate event type '${eventType}' - event types can only be used once at each level`));
880
- } else {
881
- currentEventContext.set(eventType, { lineNumber, col });
882
- }
883
- }
884
- const removeWithMatch = trimmed.match(/^remove\s+(?:with|via\s+join\s+on)\s+([\w-]+)/);
885
- if (removeWithMatch) {
886
- const eventType = removeWithMatch[1];
887
- const col = line.indexOf(eventType) + 1;
888
- if (Object.keys(this.eventSchemas).length > 0 && !this.eventSchemas[eventType]) {
889
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Event type '${eventType}' not found`));
890
- }
891
- if (currentEventContext.has(eventType)) {
892
- markers.push(this.createError(lineNumber, col, col + eventType.length, `Duplicate event type '${eventType}' - event types can only be used once at each level`));
893
- } else {
894
- currentEventContext.set(eventType, { lineNumber, col });
895
- }
896
- }
897
- const assignmentMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
898
- if (assignmentMatch) {
899
- const currentSchema = contextStack[contextStack.length - 1];
900
- if (currentSchema?.properties) {
901
- const [, propertyName] = assignmentMatch;
902
- if (!currentSchema.properties[propertyName]) {
903
- const col = line.indexOf(propertyName) + 1;
904
- const schemaName = this.getSchemaName(currentSchema) || "current schema";
905
- markers.push(this.createWarning(lineNumber, col, col + propertyName.length, `Property '${propertyName}' not found in ${schemaName}`));
906
- }
907
- }
908
- }
909
- const numericOpMatch = trimmed.match(/^(?:increment|decrement|count)\s+(\w+)$/);
910
- if (numericOpMatch) {
911
- const currentSchema = contextStack[contextStack.length - 1];
912
- if (currentSchema?.properties) {
913
- const [, propertyName] = numericOpMatch;
914
- if (!currentSchema.properties[propertyName]) {
915
- const col = line.indexOf(propertyName) + 1;
916
- const schemaName = this.getSchemaName(currentSchema) || "current schema";
917
- markers.push(this.createWarning(lineNumber, col, col + propertyName.length, `Property '${propertyName}' not found in ${schemaName}`));
918
- }
919
- }
920
- }
921
- const addSubMatch = trimmed.match(/^(?:add|subtract)\s+(\w+)\s+by\s+/);
922
- if (addSubMatch) {
923
- const currentSchema = contextStack[contextStack.length - 1];
924
- if (currentSchema?.properties) {
925
- const [, propertyName] = addSubMatch;
926
- if (!currentSchema.properties[propertyName]) {
927
- const col = line.indexOf(propertyName) + 1;
928
- const schemaName = this.getSchemaName(currentSchema) || "current schema";
929
- markers.push(this.createWarning(lineNumber, col, col + propertyName.length, `Property '${propertyName}' not found in ${schemaName}`));
930
- }
931
- }
932
- }
933
- const childrenMatch = trimmed.match(/^children\s+(\w+)\s+identified\s+by\s+/);
934
- if (childrenMatch) {
935
- const currentSchema = contextStack[contextStack.length - 1];
936
- if (currentSchema?.properties) {
937
- const [, propertyName] = childrenMatch;
938
- const prop = currentSchema.properties[propertyName];
939
- if (!prop) {
940
- const col = line.indexOf(propertyName) + 1;
941
- const schemaName = this.getSchemaName(currentSchema) || "current schema";
942
- markers.push(this.createWarning(lineNumber, col, col + propertyName.length, `Collection property '${propertyName}' not found in ${schemaName}`));
943
- } else if (prop.type !== "array" && !prop.items) {
944
- const col = line.indexOf(propertyName) + 1;
945
- markers.push(this.createWarning(lineNumber, col, col + propertyName.length, `Property '${propertyName}' is not a collection (array) type`));
946
- } else {
947
- const childSchema = prop.items;
948
- if (childSchema) {
949
- contextStack.push(childSchema);
950
- indentStack.push(currentIndent);
951
- eventContextStack.push(/* @__PURE__ */ new Map());
952
- }
953
- }
954
- }
955
- }
956
- const joinMatch = trimmed.match(/^join\s+(\w+)\s+on\s+(\w+)/);
957
- if (joinMatch && activeSchema?.properties) {
958
- const [, collectionName, joinProperty] = joinMatch;
959
- const collectionProp = activeSchema.properties[collectionName];
960
- if (!collectionProp) {
961
- const col = line.indexOf(collectionName) + 1;
962
- markers.push(this.createWarning(lineNumber, col, col + collectionName.length, `Collection property '${collectionName}' not found in read model '${readModelName}'`));
963
- } else if (collectionProp.type !== "array" && !collectionProp.items) {
964
- const col = line.indexOf(collectionName) + 1;
965
- markers.push(this.createWarning(lineNumber, col, col + collectionName.length, `Property '${collectionName}' is not a collection (array) type`));
966
- }
967
- if (!activeSchema.properties[joinProperty]) {
968
- const col = line.indexOf(joinProperty, line.indexOf("on")) + 1;
969
- markers.push(this.createWarning(lineNumber, col, col + joinProperty.length, `Property '${joinProperty}' not found in read model '${readModelName}'`));
970
- }
971
- eventContextStack.push(/* @__PURE__ */ new Map());
972
- indentStack.push(currentIndent);
973
- }
974
- const keyMatch = trimmed.match(/^key\s+(\w+)\s*$/);
975
- if (keyMatch && activeSchema) {
976
- const [, keyName] = keyMatch;
977
- const isInDefinitions = activeSchema.definitions && activeSchema.definitions[keyName];
978
- const isProperty = activeSchema.properties && activeSchema.properties[keyName];
979
- if (!isInDefinitions && !isProperty && !this.isBuiltInExpression(keyName)) {
980
- const col = line.indexOf(keyName) + 1;
981
- markers.push(this.createWarning(lineNumber, col, col + keyName.length, `Composite key type '${keyName}' not found in read model schema`));
982
- }
983
- }
984
- }
985
- for (const issue of validateEventContextPaths(lines, fenceMap(lines))) {
986
- markers.push({
987
- severity: issue.severity === "error" ? 8 : 4,
988
- startLineNumber: issue.line + 1,
989
- endLineNumber: issue.line + 1,
990
- startColumn: issue.startColumn,
991
- endColumn: issue.endColumn,
992
- message: issue.message,
993
- code: issue.code
994
- });
995
- }
996
- return markers;
997
- }
998
- resolveReadModelInfo(readModelToken) {
999
- return this.readModels.find((rm) => rm.identifier === readModelToken || rm.displayName === readModelToken) || null;
1000
- }
1001
- getReadModelStartColumn(firstLine, readModelName) {
1002
- const prefixMatch = firstLine.match(/^\s*projection\s+[\w.]+\s*=>\s*/);
1003
- if (!prefixMatch) {
1004
- const fallbackIndex = firstLine.lastIndexOf(readModelName);
1005
- return (fallbackIndex >= 0 ? fallbackIndex : 0) + 1;
1006
- }
1007
- return prefixMatch[0].length + 1;
1008
- }
1009
- resolveReadModelIdentifier(readModelToken) {
1010
- if (this.isDraftReadModel(readModelToken)) {
1011
- return this.draftReadModel.identifier;
1012
- }
1013
- const readModel = this.resolveReadModelInfo(readModelToken);
1014
- return readModel?.identifier ?? null;
1015
- }
1016
- isDraftReadModel(readModelToken) {
1017
- return !!this.draftReadModel && (this.draftReadModel.identifier === readModelToken || this.draftReadModel.displayName === readModelToken);
1018
- }
1019
- isBuiltInExpression(text) {
1020
- return text.startsWith("$") || ["true", "false", "null"].includes(text);
1021
- }
1022
- createError(line, startCol, endCol, message) {
1023
- return {
1024
- severity: 8,
1025
- // Error
1026
- startLineNumber: line,
1027
- startColumn: startCol,
1028
- endLineNumber: line,
1029
- endColumn: endCol,
1030
- message
1031
- };
1032
- }
1033
- createWarning(line, startCol, endCol, message) {
1034
- return {
1035
- severity: 4,
1036
- // Warning
1037
- startLineNumber: line,
1038
- startColumn: startCol,
1039
- endLineNumber: line,
1040
- endColumn: endCol,
1041
- message
1042
- };
1043
- }
1044
- createInfo(line, startCol, endCol, message) {
1045
- return {
1046
- severity: 2,
1047
- // Info (hint) - shows as blue/green squiggly
1048
- startLineNumber: line,
1049
- startColumn: startCol,
1050
- endLineNumber: line,
1051
- endColumn: endCol,
1052
- message
1053
- };
1054
- }
1055
- getSchemaName(schema) {
1056
- if (schema.name) return schema.name;
1057
- if (schema.title) return schema.title;
1058
- if (typeof schema.$id === "string") {
1059
- const parts = schema.$id.split("/");
1060
- return parts[parts.length - 1] || schema.$id;
1061
- }
1062
- return void 0;
1063
- }
1064
- };
10
+ ${properties.map(p=>`- \`${p.name}\`: ${p.type}`).join(`
11
+ `)}`),{contents:[{value:content}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}}}if(this.isDraftReadModel(wordText)){let description=this.getSchemaDescription(this.draftReadModel.schema),properties=this.getSchemaProperties(this.draftReadModel.schema),identifier=this.draftReadModel.identifier,content=`**Read Model (Draft):** \`${this.draftReadModel.displayName}\`
1065
12
 
1066
- // sub-languages/projection/HoverProvider.ts
1067
- var HoverProvider = class {
1068
- readModels = [];
1069
- eventSchemas = {};
1070
- draftReadModel = null;
1071
- setReadModels(readModels) {
1072
- this.readModels = readModels || [];
1073
- }
1074
- // Keep for backwards compatibility
1075
- setReadModelSchemas(schemas) {
1076
- this.readModels = schemas.map((schema) => ({
1077
- identifier: this.getSchemaName(schema) || "",
1078
- displayName: this.getSchemaName(schema) || "",
1079
- schema
1080
- }));
1081
- }
1082
- setEventSchemas(schemas) {
1083
- if (!schemas) {
1084
- this.eventSchemas = {};
1085
- return;
1086
- }
1087
- if (Array.isArray(schemas)) {
1088
- const map = {};
1089
- schemas.forEach((s, i) => {
1090
- if (!s) return;
1091
- const name = this.getSchemaName(s) || `Event${i + 1}`;
1092
- map[name] = s;
1093
- });
1094
- this.eventSchemas = map;
1095
- return;
1096
- }
1097
- this.eventSchemas = schemas;
1098
- }
1099
- setDraftReadModel(draft) {
1100
- this.draftReadModel = draft;
1101
- }
1102
- provideHover(model, position) {
1103
- const word = model.getWordAtPosition(position);
1104
- if (!word) return null;
1105
- const wordText = word.word;
1106
- const lineContent = model.getLineContent(position.lineNumber);
1107
- const projectionNameMatch = this.getProjectionNameAtPosition(lineContent, position.column);
1108
- if (projectionNameMatch) {
1109
- return {
1110
- contents: [{ value: "The name of the projection" }],
1111
- range: {
1112
- startLineNumber: position.lineNumber,
1113
- startColumn: word.startColumn,
1114
- endLineNumber: position.lineNumber,
1115
- endColumn: word.endColumn
1116
- }
1117
- };
1118
- }
1119
- const eventContextInfo = this.getEventContextInfo(lineContent, word.startColumn);
1120
- if (eventContextInfo) {
1121
- return {
1122
- contents: [{ value: eventContextInfo }],
1123
- range: {
1124
- startLineNumber: position.lineNumber,
1125
- startColumn: word.startColumn,
1126
- endLineNumber: position.lineNumber,
1127
- endColumn: word.endColumn
1128
- }
1129
- };
1130
- }
1131
- const keywordInfo = this.getKeywordInfo(wordText);
1132
- if (keywordInfo) {
1133
- return {
1134
- contents: [{ value: keywordInfo }],
1135
- range: {
1136
- startLineNumber: position.lineNumber,
1137
- startColumn: word.startColumn,
1138
- endLineNumber: position.lineNumber,
1139
- endColumn: word.endColumn
1140
- }
1141
- };
1142
- }
1143
- const expressionInfo = this.getExpressionInfo(wordText);
1144
- if (expressionInfo) {
1145
- return {
1146
- contents: [{ value: expressionInfo }],
1147
- range: {
1148
- startLineNumber: position.lineNumber,
1149
- startColumn: word.startColumn,
1150
- endLineNumber: position.lineNumber,
1151
- endColumn: word.endColumn
1152
- }
1153
- };
1154
- }
1155
- if (this.eventSchemas[wordText]) {
1156
- const schema = this.eventSchemas[wordText];
1157
- const description = this.getSchemaDescription(schema);
1158
- const properties = this.getSchemaProperties(schema);
1159
- let content = `**Event Type:** \`${wordText}\`
13
+ **Identifier:** \`${identifier}\`
1160
14
 
1161
- `;
1162
- if (description) {
1163
- content += `${description}
15
+ `;return description&&(content+=`${description}
1164
16
 
1165
- `;
1166
- }
1167
- if (properties.length > 0) {
1168
- content += `**Properties:**
17
+ `),properties.length>0&&(content+=`**Properties:**
1169
18
 
1170
- ${properties.map((p) => `- \`${p.name}\`: ${p.type}`).join("\n")}`;
1171
- }
1172
- return {
1173
- contents: [{ value: content }],
1174
- range: {
1175
- startLineNumber: position.lineNumber,
1176
- startColumn: word.startColumn,
1177
- endLineNumber: position.lineNumber,
1178
- endColumn: word.endColumn
1179
- }
1180
- };
1181
- }
1182
- if (this.isDraftReadModel(wordText)) {
1183
- const description = this.getSchemaDescription(this.draftReadModel.schema);
1184
- const properties = this.getSchemaProperties(this.draftReadModel.schema);
1185
- const identifier = this.draftReadModel.identifier;
1186
- const displayName = this.draftReadModel.displayName;
1187
- let content = `**Read Model (Draft):** \`${displayName}\`
19
+ ${properties.map(p=>`- \`${p.name}\`: ${p.type}`).join(`
20
+ `)}`),{contents:[{value:content}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}}}let readModel=this.resolveReadModelInfo(wordText);if(readModel){let description=this.getSchemaDescription(readModel.schema),properties=this.getSchemaProperties(readModel.schema),content=`**Read Model:** \`${readModel.displayName}\`
1188
21
 
1189
- **Identifier:** \`${identifier}\`
22
+ **Identifier:** \`${readModel.identifier}\`
1190
23
 
1191
- `;
1192
- if (description) {
1193
- content += `${description}
24
+ `;return description&&(content+=`${description}
1194
25
 
1195
- `;
1196
- }
1197
- if (properties.length > 0) {
1198
- content += `**Properties:**
26
+ `),properties.length>0&&(content+=`**Properties:**
1199
27
 
1200
- ${properties.map((p) => `- \`${p.name}\`: ${p.type}`).join("\n")}`;
1201
- }
1202
- return {
1203
- contents: [{ value: content }],
1204
- range: {
1205
- startLineNumber: position.lineNumber,
1206
- startColumn: word.startColumn,
1207
- endLineNumber: position.lineNumber,
1208
- endColumn: word.endColumn
1209
- }
1210
- };
1211
- }
1212
- const readModel = this.resolveReadModelInfo(wordText);
1213
- if (readModel) {
1214
- const description = this.getSchemaDescription(readModel.schema);
1215
- const properties = this.getSchemaProperties(readModel.schema);
1216
- let content = `**Read Model:** \`${readModel.displayName}\`
28
+ ${properties.map(p=>`- \`${p.name}\`: ${p.type}`).join(`
29
+ `)}`),{contents:[{value:content}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}}}let propertyInfo=this.getPropertyInfo(model,position,wordText);return propertyInfo?{contents:[{value:propertyInfo}],range:{startLineNumber:position.lineNumber,startColumn:word.startColumn,endLineNumber:position.lineNumber,endColumn:word.endColumn}}:null}getKeywordInfo(word){return{projection:"**projection** - Defines a projection that transforms events into a read model",from:`**from** *<EventType>*
1217
30
 
1218
- **Identifier:** \`${readModel.identifier}\`
31
+ Handles specific event types and maps their properties to the read model.`,all:"**all**\n\nSubscribes to **all event types in the system**, regardless of explicit `from` blocks. Mappings inside `all` run for every event that arrives system-wide.",every:"**every**\n\nHandles all events the projection **explicitly subscribes to** through `from` blocks, with automatic property mapping.",key:`**key** *<expression>*
32
+
33
+ Defines the projection key or composite key type.`,parent:`**parent** *<expression>*
34
+
35
+ Defines a parent relationship for hierarchical projections.`,join:`**join** *<collection>* **on** *<property>*
36
+
37
+ Joins with a child collection based on a property.`,children:`**children** *<collection>* **id** *<expression>*
38
+
39
+ Defines operations on child collections.`,remove:`**remove with** *<EventType>* or **remove via join on** *<EventType>*
40
+
41
+ Removes items from the read model based on events.`,clear:`**clear** *<property>*
42
+
43
+ Removes the value a property holds. **clear with** *<EventType>* nulls a whole nested object instead.`,automap:`**automap** or **no automap**
44
+
45
+ Controls automatic property mapping from events to the read model.`,increment:`**increment** *<property>*
46
+
47
+ Increments a numeric property by 1.`,decrement:`**decrement** *<property>*
48
+
49
+ Decrements a numeric property by 1.`,count:`**count** *<property>*
50
+
51
+ Counts occurrences and stores in a property.`,add:`**add** *<property>* **by** *<expression>*
52
+
53
+ Adds a value to a property.`,subtract:`**subtract** *<property>* **by** *<expression>*
54
+
55
+ Subtracts a value from a property.`,exclude:`**exclude children**
1219
56
 
1220
- `;
1221
- if (description) {
1222
- content += `${description}
57
+ Excludes child collections from automatic mapping.`,events:`**events** *<EventType>*, ...
1223
58
 
1224
- `;
1225
- }
1226
- if (properties.length > 0) {
1227
- content += `**Properties:**
59
+ Specifies which event types to include in a join.`,via:"Used with **remove via join on** to remove items via a join relationship.",with:"Used with **remove with** to specify which event type triggers removal.",on:"Used with **join** to specify the join property.",by:"Used with **add** or **subtract** to specify the value.",id:"Used with **children** to specify the child identifier expression.",no:"Used with **no automap** to disable automatic property mapping.",variant:`**variant** *<Name>*
1228
60
 
1229
- ${properties.map((p) => `- \`${p.name}\`: ${p.type}`).join("\n")}`;
1230
- }
1231
- return {
1232
- contents: [{ value: content }],
1233
- range: {
1234
- startLineNumber: position.lineNumber,
1235
- startColumn: word.startColumn,
1236
- endLineNumber: position.lineNumber,
1237
- endColumn: word.endColumn
1238
- }
1239
- };
1240
- }
1241
- const propertyInfo = this.getPropertyInfo(model, position, wordText);
1242
- if (propertyInfo) {
1243
- return {
1244
- contents: [{ value: propertyInfo }],
1245
- range: {
1246
- startLineNumber: position.lineNumber,
1247
- startColumn: word.startColumn,
1248
- endLineNumber: position.lineNumber,
1249
- endColumn: word.endColumn
1250
- }
1251
- };
1252
- }
1253
- return null;
1254
- }
1255
- getKeywordInfo(word) {
1256
- const keywords = {
1257
- "projection": "**projection** - Defines a projection that transforms events into a read model",
1258
- "from": "**from** *<EventType>*\n\nHandles specific event types and maps their properties to the read model.",
1259
- "all": "**all**\n\nSubscribes to **all event types in the system**, regardless of explicit `from` blocks. Mappings inside `all` run for every event that arrives system-wide.",
1260
- "every": "**every**\n\nHandles all events the projection **explicitly subscribes to** through `from` blocks, with automatic property mapping.",
1261
- "key": "**key** *<expression>*\n\nDefines the projection key or composite key type.",
1262
- "parent": "**parent** *<expression>*\n\nDefines a parent relationship for hierarchical projections.",
1263
- "join": "**join** *<collection>* **on** *<property>*\n\nJoins with a child collection based on a property.",
1264
- "children": "**children** *<collection>* **id** *<expression>*\n\nDefines operations on child collections.",
1265
- "remove": "**remove with** *<EventType>* or **remove via join on** *<EventType>*\n\nRemoves items from the read model based on events.",
1266
- "clear": "**clear** *<property>*\n\nRemoves the value a property holds. **clear with** *<EventType>* nulls a whole nested object instead.",
1267
- "automap": "**automap** or **no automap**\n\nControls automatic property mapping from events to the read model.",
1268
- "increment": "**increment** *<property>*\n\nIncrements a numeric property by 1.",
1269
- "decrement": "**decrement** *<property>*\n\nDecrements a numeric property by 1.",
1270
- "count": "**count** *<property>*\n\nCounts occurrences and stores in a property.",
1271
- "add": "**add** *<property>* **by** *<expression>*\n\nAdds a value to a property.",
1272
- "subtract": "**subtract** *<property>* **by** *<expression>*\n\nSubtracts a value from a property.",
1273
- "exclude": "**exclude children**\n\nExcludes child collections from automatic mapping.",
1274
- "events": "**events** *<EventType>*, ...\n\nSpecifies which event types to include in a join.",
1275
- "via": "Used with **remove via join on** to remove items via a join relationship.",
1276
- "with": "Used with **remove with** to specify which event type triggers removal.",
1277
- "on": "Used with **join** to specify the join property.",
1278
- "by": "Used with **add** or **subtract** to specify the value.",
1279
- "id": "Used with **children** to specify the child identifier expression.",
1280
- "no": "Used with **no automap** to disable automatic property mapping.",
1281
- "variant": "**variant** *<Name>*\n\nDeclares one of several mutually exclusive named read models sharing the projection's identity. Entering one variant removes the entity from every other variant of the same projection.",
1282
- "enters": "**enters on** *<EventType>*\n\nDeclares the event that activates this variant - the only event allowed to create it. Every other event the variant subscribes to is update-only."
1283
- };
1284
- return keywords[word] || null;
1285
- }
1286
- getExpressionInfo(word) {
1287
- const expressions = {
1288
- "$eventSourceId": "**$eventSourceId**\n\nThe identifier of the event source (aggregate/entity) that generated the event.",
1289
- "$causedBy": "**$causedBy**\n\nThe identity that caused the event - `subject`, `name`, `userName` or `onBehalfOf`, itself an identity.\n\nChronicle cannot yet evaluate this short form (Cratis/Chronicle#4119); prefer **$eventContext.causedBy**.*property*.",
1290
- "$eventContext": describeEventContext()
1291
- };
1292
- return expressions[word] || null;
1293
- }
1294
- // Describes the $eventContext path segment starting at the given column, if the word there is one.
1295
- getEventContextInfo(lineContent, startColumn) {
1296
- for (const match of lineContent.matchAll(/\$eventContext((?:\.\w+(?:\(\))?)*)/g)) {
1297
- let column = (match.index ?? 0) + 1;
1298
- if (startColumn === column) return describeEventContext();
1299
- column += "$eventContext".length;
1300
- const segments = match[1].split(".").slice(1);
1301
- for (let index = 0; index < segments.length; index++) {
1302
- column += 1;
1303
- if (startColumn === column) {
1304
- const path = segments.slice(0, index + 1);
1305
- const member = eventContextMemberAt(path);
1306
- return member ? describeEventContextMember(path.join("."), member) : null;
1307
- }
1308
- column += segments[index].length;
1309
- }
1310
- }
1311
- return null;
1312
- }
1313
- getPropertyInfo(model, position, propertyName) {
1314
- const firstLine = model.getLineContent(1).trim();
1315
- const match = firstLine.match(/^projection\s+[\w.]+\s*=>\s*([\w.]+)/);
1316
- if (!match) return null;
1317
- const readModelName = match[1];
1318
- const draftMatch = this.isDraftReadModel(readModelName) ? this.draftReadModel : null;
1319
- const resolvedReadModel = draftMatch ? null : this.resolveReadModelInfo(readModelName);
1320
- const activeSchema = draftMatch?.schema || resolvedReadModel?.schema;
1321
- if (activeSchema?.properties && activeSchema.properties[propertyName]) {
1322
- const prop = activeSchema.properties[propertyName];
1323
- const type = this.getPropertyTypeDescription(prop);
1324
- const description = prop.description;
1325
- let content = `**Property:** \`${propertyName}\`
61
+ Declares one of several mutually exclusive named read models sharing the projection's identity. Entering one variant removes the entity from every other variant of the same projection.`,enters:`**enters on** *<EventType>*
1326
62
 
1327
- **Type:** \`${type}\``;
1328
- if (description) {
1329
- content += `
63
+ Declares the event that activates this variant - the only event allowed to create it. Every other event the variant subscribes to is update-only.`}[word]||null}getExpressionInfo(word){return{$eventSourceId:`**$eventSourceId**
1330
64
 
1331
- ${description}`;
1332
- }
1333
- return content;
1334
- }
1335
- const eventType = this.getCurrentEventType(model, position.lineNumber);
1336
- if (eventType && this.eventSchemas[eventType]) {
1337
- const eventSchema = this.eventSchemas[eventType];
1338
- if (eventSchema.properties && eventSchema.properties[propertyName]) {
1339
- const prop = eventSchema.properties[propertyName];
1340
- const type = this.getPropertyTypeDescription(prop);
1341
- const description = prop.description;
1342
- let content = `**Event Property:** \`${propertyName}\`
65
+ The identifier of the event source (aggregate/entity) that generated the event.`,$causedBy:"**$causedBy**\n\nThe identity that caused the event - `subject`, `name`, `userName` or `onBehalfOf`, itself an identity.\n\nChronicle cannot yet evaluate this short form (Cratis/Chronicle#4119); prefer **$eventContext.causedBy**.*property*.",$eventContext:describeEventContext()}[word]||null}getEventContextInfo(lineContent,startColumn){for(let match of lineContent.matchAll(/\$eventContext((?:\.\w+(?:\(\))?)*)/g)){let column=(match.index??0)+1;if(startColumn===column)return describeEventContext();column+=13;let segments=match[1].split(".").slice(1);for(let index=0;index<segments.length;index++){if(column+=1,startColumn===column){let path=segments.slice(0,index+1),member=eventContextMemberAt(path);return member?describeEventContextMember(path.join("."),member):null}column+=segments[index].length}}return null}getPropertyInfo(model,position,propertyName){let match=model.getLineContent(1).trim().match(/^projection\s+[\w.]+\s*=>\s*([\w.]+)/);if(!match)return null;let readModelName=match[1],draftMatch=this.isDraftReadModel(readModelName)?this.draftReadModel:null,resolvedReadModel=draftMatch?null:this.resolveReadModelInfo(readModelName),activeSchema=draftMatch?.schema||resolvedReadModel?.schema;if(activeSchema?.properties&&activeSchema.properties[propertyName]){let prop=activeSchema.properties[propertyName],type=this.getPropertyTypeDescription(prop),description=prop.description,content=`**Property:** \`${propertyName}\`
1343
66
 
1344
- **Type:** \`${type}\``;
1345
- if (description) {
1346
- content += `
67
+ **Type:** \`${type}\``;return description&&(content+=`
1347
68
 
1348
- ${description}`;
1349
- }
1350
- return content;
1351
- }
1352
- }
1353
- return null;
1354
- }
1355
- resolveReadModelInfo(readModelToken) {
1356
- return this.readModels.find((rm) => rm.identifier === readModelToken || rm.displayName === readModelToken) || null;
1357
- }
1358
- isDraftReadModel(readModelToken) {
1359
- return !!this.draftReadModel && (this.draftReadModel.identifier === readModelToken || this.draftReadModel.displayName === readModelToken);
1360
- }
1361
- getCurrentEventType(model, lineNumber) {
1362
- for (let i = lineNumber; i >= 1; i--) {
1363
- const line = model.getLineContent(i).trim();
1364
- const fromMatch = line.match(/^from\s+([\w-]+)/);
1365
- if (fromMatch) {
1366
- return fromMatch[1];
1367
- }
1368
- }
1369
- return null;
1370
- }
1371
- getProjectionNameAtPosition(lineContent, column) {
1372
- const projectionMatch = lineContent.match(/^\s*projection\s+(\S+)\s*=>/);
1373
- if (!projectionMatch) return false;
1374
- const projectionKeywordEnd = lineContent.indexOf("projection") + "projection".length;
1375
- const arrowStart = lineContent.indexOf("=>");
1376
- return column > projectionKeywordEnd && column <= arrowStart;
1377
- }
1378
- getSchemaName(schema) {
1379
- if (schema.name) return schema.name;
1380
- if (schema.title) return schema.title;
1381
- if (typeof schema.$id === "string") {
1382
- const parts = schema.$id.split("/");
1383
- return parts[parts.length - 1] || schema.$id;
1384
- }
1385
- return void 0;
1386
- }
1387
- getSchemaDescription(schema) {
1388
- return schema.description || void 0;
1389
- }
1390
- getSchemaProperties(schema) {
1391
- if (!schema.properties) return [];
1392
- return Object.entries(schema.properties).map(([name, prop]) => ({
1393
- name,
1394
- type: this.getPropertyTypeDescription(prop)
1395
- }));
1396
- }
1397
- getPropertyTypeDescription(propSchema) {
1398
- if (propSchema.type === "array" && propSchema.items) {
1399
- const itemType = propSchema.items.type || propSchema.items.$ref?.split("/").pop() || "unknown";
1400
- return `${itemType}[]`;
1401
- }
1402
- return propSchema.type || propSchema.$ref?.split("/").pop() || "unknown";
1403
- }
1404
- };
69
+ ${description}`),content}let eventType=this.getCurrentEventType(model,position.lineNumber);if(eventType&&this.eventSchemas[eventType]){let eventSchema=this.eventSchemas[eventType];if(eventSchema.properties&&eventSchema.properties[propertyName]){let prop=eventSchema.properties[propertyName],type=this.getPropertyTypeDescription(prop),description=prop.description,content=`**Event Property:** \`${propertyName}\`
1405
70
 
1406
- // sub-languages/projection/CodeActionProvider.ts
1407
- var CodeActionProvider = class {
1408
- readModels = [];
1409
- draftReadModel = null;
1410
- onCreateReadModel;
1411
- onEditReadModel;
1412
- setReadModels(readModels) {
1413
- this.readModels = readModels;
1414
- }
1415
- setDraftReadModel(draft) {
1416
- this.draftReadModel = draft;
1417
- }
1418
- // Keep for backwards compatibility
1419
- setReadModelSchemas(schemas) {
1420
- this.readModels = schemas.map((schema) => ({
1421
- identifier: schema.title || schema.name || "",
1422
- displayName: schema.title || schema.name || "",
1423
- schema
1424
- }));
1425
- }
1426
- setCreateReadModelCallback(callback) {
1427
- this.onCreateReadModel = callback;
1428
- }
1429
- setEditReadModelCallback(callback) {
1430
- this.onEditReadModel = callback;
1431
- }
1432
- invokeCreateReadModel(readModelName) {
1433
- this.onCreateReadModel?.(readModelName);
1434
- }
1435
- invokeEditReadModel(readModelName, currentSchema) {
1436
- this.onEditReadModel?.(readModelName, currentSchema);
1437
- }
1438
- provideCodeActions(_model, _range, context) {
1439
- const actions = [];
1440
- const notFoundDiagnostics = context.markers.filter(
1441
- (marker) => marker.message.includes("Read model") && marker.message.includes("not found")
1442
- );
1443
- const draftDiagnostics = context.markers.filter(
1444
- (marker) => marker.message.includes("Read model") && marker.message.includes("is a draft")
1445
- );
1446
- for (const diagnostic of notFoundDiagnostics) {
1447
- const match = diagnostic.message.match(/Read model ['"]([\w.]+)['"]/);
1448
- if (match && match[1]) {
1449
- const readModelName = match[1];
1450
- const existsAsPersisted = this.readModels.some(
1451
- (rm) => rm.identifier === readModelName || rm.displayName === readModelName
1452
- );
1453
- if (!existsAsPersisted && this.onCreateReadModel) {
1454
- actions.push({
1455
- title: `Create read model '${readModelName}'`,
1456
- diagnostics: [diagnostic],
1457
- kind: "quickfix",
1458
- edit: void 0,
1459
- isPreferred: true,
1460
- command: {
1461
- id: "pdl.createReadModel",
1462
- title: `Create ${readModelName}`,
1463
- arguments: [readModelName]
1464
- }
1465
- });
1466
- }
1467
- }
1468
- }
1469
- for (const diagnostic of draftDiagnostics) {
1470
- const match = diagnostic.message.match(/Read model ['"]([\w.]+)['"]/);
1471
- if (match && match[1]) {
1472
- const readModelName = match[1];
1473
- if (this.draftReadModel && this.isDraftReadModel(readModelName) && this.onEditReadModel) {
1474
- actions.push({
1475
- title: `Edit read model '${readModelName}'`,
1476
- diagnostics: [diagnostic],
1477
- kind: "quickfix",
1478
- edit: void 0,
1479
- isPreferred: true,
1480
- command: {
1481
- id: "pdl.editReadModel",
1482
- title: `Edit ${readModelName}`,
1483
- arguments: [readModelName, this.draftReadModel.schema]
1484
- }
1485
- });
1486
- }
1487
- }
1488
- }
1489
- return {
1490
- actions,
1491
- dispose: () => {
1492
- }
1493
- };
1494
- }
1495
- isDraftReadModel(readModelToken) {
1496
- return !!this.draftReadModel && (this.draftReadModel.identifier === readModelToken || this.draftReadModel.displayName === readModelToken);
1497
- }
1498
- };
71
+ **Type:** \`${type}\``;return description&&(content+=`
1499
72
 
1500
- // sub-languages/projection/index.ts
1501
- var validator;
1502
- var completionProvider;
1503
- var hoverProvider;
1504
- var codeActionProvider;
1505
- var disposables = [];
1506
- var monacoInstance = null;
1507
- var isRegistered = false;
1508
- var pendingCreateReadModelCallback = null;
1509
- var pendingEditReadModelCallback = null;
1510
- function registerProjectionLanguage(monaco) {
1511
- if (!isRegistered) {
1512
- isRegistered = true;
1513
- monacoInstance = monaco;
1514
- monaco.languages.register({ id: languageId });
1515
- monaco.languages.setLanguageConfiguration(languageId, configuration);
1516
- monaco.languages.setMonarchTokensProvider(languageId, monarchLanguage);
1517
- validator = new Validator();
1518
- completionProvider = new CompletionProvider();
1519
- hoverProvider = new HoverProvider();
1520
- codeActionProvider = new CodeActionProvider();
1521
- if (pendingCreateReadModelCallback) {
1522
- codeActionProvider.setCreateReadModelCallback(pendingCreateReadModelCallback);
1523
- pendingCreateReadModelCallback = null;
1524
- }
1525
- if (pendingEditReadModelCallback) {
1526
- codeActionProvider.setEditReadModelCallback(pendingEditReadModelCallback);
1527
- pendingEditReadModelCallback = null;
1528
- }
1529
- disposables.push(monaco.languages.registerCompletionItemProvider(languageId, {
1530
- provideCompletionItems: completionProvider.provideCompletionItems.bind(completionProvider),
1531
- triggerCharacters: [".", " ", "=", "\n", "$"]
1532
- }));
1533
- disposables.push(monaco.languages.registerHoverProvider(languageId, {
1534
- provideHover: hoverProvider.provideHover.bind(hoverProvider)
1535
- }));
1536
- disposables.push(monaco.languages.registerCodeActionProvider(languageId, {
1537
- provideCodeActions: codeActionProvider.provideCodeActions.bind(codeActionProvider)
1538
- }, {
1539
- providedCodeActionKinds: ["quickfix"]
1540
- }));
1541
- disposables.push(monaco.editor.registerCommand("pdl.createReadModel", (_accessor, readModelName) => {
1542
- codeActionProvider?.invokeCreateReadModel(readModelName);
1543
- }));
1544
- disposables.push(monaco.editor.registerCommand("pdl.editReadModel", (_accessor, readModelName, currentSchema) => {
1545
- codeActionProvider?.invokeEditReadModel(readModelName, currentSchema);
1546
- }));
1547
- disposables.push(monaco.editor.onDidCreateModel((model) => {
1548
- if (model.getLanguageId() === languageId) {
1549
- validateModel(monaco, model);
1550
- disposables.push(model.onDidChangeContent(() => validateModel(monaco, model)));
1551
- }
1552
- }));
1553
- monaco.editor.getModels().forEach((model) => {
1554
- if (model.getLanguageId() === languageId) {
1555
- validateModel(monaco, model);
1556
- }
1557
- });
1558
- }
1559
- return { dispose };
1560
- }
1561
- function dispose() {
1562
- disposables.forEach((disposable) => disposable.dispose());
1563
- disposables = [];
1564
- isRegistered = false;
1565
- monacoInstance = null;
1566
- }
1567
- function setReadModelSchema(schema) {
1568
- validator?.setReadModelSchemas([schema]);
1569
- completionProvider?.setReadModelSchemas([schema]);
1570
- }
1571
- function setReadModelSchemas(readModels) {
1572
- validator?.setReadModels(readModels);
1573
- completionProvider?.setReadModels(readModels);
1574
- hoverProvider?.setReadModels(readModels);
1575
- codeActionProvider?.setReadModels(readModels);
1576
- revalidateAllModels();
1577
- }
1578
- function setCreateReadModelCallback(callback) {
1579
- if (codeActionProvider) {
1580
- codeActionProvider.setCreateReadModelCallback(callback);
1581
- } else {
1582
- pendingCreateReadModelCallback = callback;
1583
- }
1584
- }
1585
- function setEditReadModelCallback(callback) {
1586
- if (codeActionProvider) {
1587
- codeActionProvider.setEditReadModelCallback(callback);
1588
- } else {
1589
- pendingEditReadModelCallback = callback;
1590
- }
1591
- }
1592
- function setDraftReadModel(draft) {
1593
- codeActionProvider?.setDraftReadModel(draft);
1594
- validator?.setDraftReadModel(draft);
1595
- hoverProvider?.setDraftReadModel(draft);
1596
- revalidateAllModels();
1597
- }
1598
- function setEventSchemas(eventSchemas) {
1599
- const normalize = (input) => {
1600
- if (!input) return {};
1601
- if (Array.isArray(input)) {
1602
- const out = {};
1603
- input.forEach((s, i) => {
1604
- if (!s) return;
1605
- const name = s.title || s.name || (typeof s.$id === "string" ? s.$id.split("/").pop() : void 0) || `Event${i + 1}`;
1606
- out[name] = s;
1607
- });
1608
- return out;
1609
- }
1610
- return input;
1611
- };
1612
- const normalized = normalize(eventSchemas);
1613
- validator?.setEventSchemas(normalized);
1614
- completionProvider?.setEventSchemas(normalized);
1615
- hoverProvider?.setEventSchemas(normalized);
1616
- revalidateAllModels();
1617
- }
1618
- function setEventSequences(sequences) {
1619
- completionProvider?.setEventSequences(sequences);
1620
- }
1621
- function validateModel(monaco, model) {
1622
- if (validator && !model.isDisposed()) {
1623
- const markers = validator.validate(model);
1624
- monaco.editor.setModelMarkers(model, "pdl-validator", markers);
1625
- }
1626
- }
1627
- function revalidateAllModels() {
1628
- if (monacoInstance) {
1629
- monacoInstance.editor.getModels().forEach((model) => {
1630
- if (model.getLanguageId() === languageId) {
1631
- validateModel(monacoInstance, model);
1632
- }
1633
- });
1634
- }
1635
- }
1636
- export {
1637
- languageId,
1638
- registerProjectionLanguage,
1639
- setCreateReadModelCallback,
1640
- setDraftReadModel,
1641
- setEditReadModelCallback,
1642
- setEventSchemas,
1643
- setEventSequences,
1644
- setReadModelSchema,
1645
- setReadModelSchemas
1646
- };
73
+ ${description}`),content}}return null}resolveReadModelInfo(readModelToken){return this.readModels.find(rm=>rm.identifier===readModelToken||rm.displayName===readModelToken)||null}isDraftReadModel(readModelToken){return!!this.draftReadModel&&(this.draftReadModel.identifier===readModelToken||this.draftReadModel.displayName===readModelToken)}getCurrentEventType(model,lineNumber){for(let i=lineNumber;i>=1;i--){let fromMatch=model.getLineContent(i).trim().match(/^from\s+([\w-]+)/);if(fromMatch)return fromMatch[1]}return null}getProjectionNameAtPosition(lineContent,column){if(!lineContent.match(/^\s*projection\s+(\S+)\s*=>/))return!1;let projectionKeywordEnd=lineContent.indexOf("projection")+10,arrowStart=lineContent.indexOf("=>");return column>projectionKeywordEnd&&column<=arrowStart}getSchemaName(schema){if(schema.name)return schema.name;if(schema.title)return schema.title;if(typeof schema.$id=="string"){let parts=schema.$id.split("/");return parts[parts.length-1]||schema.$id}}getSchemaDescription(schema){return schema.description||void 0}getSchemaProperties(schema){return schema.properties?Object.entries(schema.properties).map(([name,prop])=>({name,type:this.getPropertyTypeDescription(prop)})):[]}getPropertyTypeDescription(propSchema){return propSchema.type==="array"&&propSchema.items?`${propSchema.items.type||propSchema.items.$ref?.split("/").pop()||"unknown"}[]`:propSchema.type||propSchema.$ref?.split("/").pop()||"unknown"}};var CodeActionProvider=class{readModels=[];draftReadModel=null;onCreateReadModel;onEditReadModel;setReadModels(readModels){this.readModels=readModels}setDraftReadModel(draft){this.draftReadModel=draft}setReadModelSchemas(schemas){this.readModels=schemas.map(schema=>({identifier:schema.title||schema.name||"",displayName:schema.title||schema.name||"",schema}))}setCreateReadModelCallback(callback){this.onCreateReadModel=callback}setEditReadModelCallback(callback){this.onEditReadModel=callback}invokeCreateReadModel(readModelName){this.onCreateReadModel?.(readModelName)}invokeEditReadModel(readModelName,currentSchema){this.onEditReadModel?.(readModelName,currentSchema)}provideCodeActions(_model,_range,context){let actions=[],notFoundDiagnostics=context.markers.filter(marker=>marker.message.includes("Read model")&&marker.message.includes("not found")),draftDiagnostics=context.markers.filter(marker=>marker.message.includes("Read model")&&marker.message.includes("is a draft"));for(let diagnostic of notFoundDiagnostics){let match=diagnostic.message.match(/Read model ['"]([\w.]+)['"]/);if(match&&match[1]){let readModelName=match[1];!this.readModels.some(rm=>rm.identifier===readModelName||rm.displayName===readModelName)&&this.onCreateReadModel&&actions.push({title:`Create read model '${readModelName}'`,diagnostics:[diagnostic],kind:"quickfix",edit:void 0,isPreferred:!0,command:{id:"pdl.createReadModel",title:`Create ${readModelName}`,arguments:[readModelName]}})}}for(let diagnostic of draftDiagnostics){let match=diagnostic.message.match(/Read model ['"]([\w.]+)['"]/);if(match&&match[1]){let readModelName=match[1];this.draftReadModel&&this.isDraftReadModel(readModelName)&&this.onEditReadModel&&actions.push({title:`Edit read model '${readModelName}'`,diagnostics:[diagnostic],kind:"quickfix",edit:void 0,isPreferred:!0,command:{id:"pdl.editReadModel",title:`Edit ${readModelName}`,arguments:[readModelName,this.draftReadModel.schema]}})}}return{actions,dispose:()=>{}}}isDraftReadModel(readModelToken){return!!this.draftReadModel&&(this.draftReadModel.identifier===readModelToken||this.draftReadModel.displayName===readModelToken)}};var validator,completionProvider,hoverProvider,codeActionProvider,disposables=[],monacoInstance=null,isRegistered=!1,pendingCreateReadModelCallback=null,pendingEditReadModelCallback=null;function registerProjectionLanguage(monaco){return isRegistered||(isRegistered=!0,monacoInstance=monaco,monaco.languages.register({id:"pdl"}),monaco.languages.setLanguageConfiguration("pdl",configuration),monaco.languages.setMonarchTokensProvider("pdl",monarchLanguage),validator=new Validator,completionProvider=new CompletionProvider,hoverProvider=new HoverProvider,codeActionProvider=new CodeActionProvider,pendingCreateReadModelCallback&&(codeActionProvider.setCreateReadModelCallback(pendingCreateReadModelCallback),pendingCreateReadModelCallback=null),pendingEditReadModelCallback&&(codeActionProvider.setEditReadModelCallback(pendingEditReadModelCallback),pendingEditReadModelCallback=null),disposables.push(monaco.languages.registerCompletionItemProvider("pdl",{provideCompletionItems:completionProvider.provideCompletionItems.bind(completionProvider),triggerCharacters:["."," ","=",`
74
+ `,"$"]})),disposables.push(monaco.languages.registerHoverProvider("pdl",{provideHover:hoverProvider.provideHover.bind(hoverProvider)})),disposables.push(monaco.languages.registerCodeActionProvider("pdl",{provideCodeActions:codeActionProvider.provideCodeActions.bind(codeActionProvider)},{providedCodeActionKinds:["quickfix"]})),disposables.push(monaco.editor.registerCommand("pdl.createReadModel",(_accessor,readModelName)=>{codeActionProvider?.invokeCreateReadModel(readModelName)})),disposables.push(monaco.editor.registerCommand("pdl.editReadModel",(_accessor,readModelName,currentSchema)=>{codeActionProvider?.invokeEditReadModel(readModelName,currentSchema)})),disposables.push(monaco.editor.onDidCreateModel(model=>{model.getLanguageId()==="pdl"&&(validateModel(monaco,model),disposables.push(model.onDidChangeContent(()=>validateModel(monaco,model))))})),monaco.editor.getModels().forEach(model=>{model.getLanguageId()==="pdl"&&validateModel(monaco,model)})),{dispose}}function dispose(){disposables.forEach(disposable=>disposable.dispose()),disposables=[],isRegistered=!1,monacoInstance=null}function setReadModelSchema(schema){validator?.setReadModelSchemas([schema]),completionProvider?.setReadModelSchemas([schema])}function setReadModelSchemas(readModels){validator?.setReadModels(readModels),completionProvider?.setReadModels(readModels),hoverProvider?.setReadModels(readModels),codeActionProvider?.setReadModels(readModels),revalidateAllModels()}function setCreateReadModelCallback(callback){codeActionProvider?codeActionProvider.setCreateReadModelCallback(callback):pendingCreateReadModelCallback=callback}function setEditReadModelCallback(callback){codeActionProvider?codeActionProvider.setEditReadModelCallback(callback):pendingEditReadModelCallback=callback}function setDraftReadModel(draft){codeActionProvider?.setDraftReadModel(draft),validator?.setDraftReadModel(draft),hoverProvider?.setDraftReadModel(draft),revalidateAllModels()}function setEventSchemas(eventSchemas){let normalized=(input=>{if(!input)return{};if(Array.isArray(input)){let out={};return input.forEach((s,i)=>{if(!s)return;let name=s.title||s.name||(typeof s.$id=="string"?s.$id.split("/").pop():void 0)||`Event${i+1}`;out[name]=s}),out}return input})(eventSchemas);validator?.setEventSchemas(normalized),completionProvider?.setEventSchemas(normalized),hoverProvider?.setEventSchemas(normalized),revalidateAllModels()}function setEventSequences(sequences){completionProvider?.setEventSequences(sequences)}function validateModel(monaco,model){if(validator&&!model.isDisposed()){let markers=validator.validate(model);monaco.editor.setModelMarkers(model,"pdl-validator",markers)}}function revalidateAllModels(){monacoInstance&&monacoInstance.editor.getModels().forEach(model=>{model.getLanguageId()==="pdl"&&validateModel(monacoInstance,model)})}export{languageId,registerProjectionLanguage,setCreateReadModelCallback,setDraftReadModel,setEditReadModelCallback,setEventSchemas,setEventSequences,setReadModelSchema,setReadModelSchemas};
1647
75
  //# sourceMappingURL=index.js.map