@cratis/screenplay-language 4.55.1 → 4.56.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.
- package/dist/AnalysisCommand.d.ts +16 -0
- package/dist/AnalysisCommand.d.ts.map +1 -0
- package/dist/AnalysisDiagnostic.d.ts +8 -0
- package/dist/AnalysisDiagnostic.d.ts.map +1 -0
- package/dist/AnalysisLocation.d.ts +6 -0
- package/dist/AnalysisLocation.d.ts.map +1 -0
- package/dist/AnalysisSpecification.d.ts +16 -0
- package/dist/AnalysisSpecification.d.ts.map +1 -0
- package/dist/AnalysisType.d.ts +6 -0
- package/dist/AnalysisType.d.ts.map +1 -0
- package/dist/AuthoringDocument.d.ts +6 -0
- package/dist/AuthoringDocument.d.ts.map +1 -0
- package/dist/CommandResponseSymbol.d.ts +13 -0
- package/dist/CommandResponseSymbol.d.ts.map +1 -0
- package/dist/ResponseAnalysis.d.ts +9 -0
- package/dist/ResponseAnalysis.d.ts.map +1 -0
- package/dist/ResponseFieldSymbol.d.ts +10 -0
- package/dist/ResponseFieldSymbol.d.ts.map +1 -0
- package/dist/ResponseSourceSymbol.d.ts +6 -0
- package/dist/ResponseSourceSymbol.d.ts.map +1 -0
- package/dist/bundles/chunk-TWF2T5S4.js +13 -0
- package/dist/bundles/chunk-TWF2T5S4.js.map +7 -0
- package/dist/bundles/index.js +18 -1362
- package/dist/bundles/index.js.map +4 -4
- package/dist/bundles/sub-languages/capture/index.js +35 -672
- package/dist/bundles/sub-languages/capture/index.js.map +1 -1
- package/dist/bundles/sub-languages/projection/index.js +53 -1625
- package/dist/bundles/sub-languages/projection/index.js.map +1 -1
- package/dist/completion-items.d.ts.map +1 -1
- package/dist/completion-planner.d.ts.map +1 -1
- package/dist/completions.d.ts +2 -0
- package/dist/completions.d.ts.map +1 -1
- package/dist/diagnostic-codes.d.ts +11 -0
- package/dist/diagnostic-codes.d.ts.map +1 -1
- package/dist/hover-content.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/response-analysis.d.ts +15 -0
- package/dist/response-analysis.d.ts.map +1 -0
- package/dist/response-completions.d.ts +4 -0
- package/dist/response-completions.d.ts.map +1 -0
- package/dist/response-tokens.d.ts +8 -0
- package/dist/response-tokens.d.ts.map +1 -0
- package/dist/symbols.d.ts +11 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -0
- package/dist/validation.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/bundles/chunk-LXM5L4YK.js +0 -4893
- package/dist/bundles/chunk-LXM5L4YK.js.map +0 -7
|
@@ -1,677 +1,40 @@
|
|
|
1
|
-
// sub-languages/capture/language.ts
|
|
2
|
-
var languageId = "cdl";
|
|
3
|
-
var KEYWORDS = [
|
|
4
|
-
"capture",
|
|
5
|
-
"source",
|
|
6
|
-
"key",
|
|
7
|
-
"map",
|
|
8
|
-
"append",
|
|
9
|
-
"when",
|
|
10
|
-
"nested",
|
|
11
|
-
"children",
|
|
12
|
-
"identified",
|
|
13
|
-
"by",
|
|
14
|
-
"api",
|
|
15
|
-
"webhook",
|
|
16
|
-
"message",
|
|
17
|
-
"route",
|
|
18
|
-
"poll",
|
|
19
|
-
"path",
|
|
20
|
-
"topic",
|
|
21
|
-
"from",
|
|
22
|
-
"to",
|
|
23
|
-
"or",
|
|
24
|
-
"and",
|
|
25
|
-
"added",
|
|
26
|
-
"removed",
|
|
27
|
-
"translate",
|
|
28
|
-
"split"
|
|
29
|
-
];
|
|
30
|
-
var BUILTINS = [
|
|
31
|
-
"$context",
|
|
32
|
-
"$previous",
|
|
33
|
-
"$env"
|
|
34
|
-
];
|
|
35
|
-
var OPERATORS = ["=", "=>", "."];
|
|
36
|
-
var languageConfiguration = {
|
|
37
|
-
comments: {
|
|
38
|
-
lineComment: "#"
|
|
39
|
-
},
|
|
40
|
-
brackets: [
|
|
41
|
-
["{", "}"],
|
|
42
|
-
["[", "]"],
|
|
43
|
-
["(", ")"]
|
|
44
|
-
],
|
|
45
|
-
autoClosingPairs: [
|
|
46
|
-
{ open: "{", close: "}" },
|
|
47
|
-
{ open: "[", close: "]" },
|
|
48
|
-
{ open: "(", close: ")" },
|
|
49
|
-
{ open: '"', close: '"' },
|
|
50
|
-
{ open: "'", close: "'" },
|
|
51
|
-
{ open: "`", close: "`" }
|
|
52
|
-
],
|
|
53
|
-
surroundingPairs: [
|
|
54
|
-
{ open: "{", close: "}" },
|
|
55
|
-
{ open: "[", close: "]" },
|
|
56
|
-
{ open: "(", close: ")" },
|
|
57
|
-
{ open: '"', close: '"' },
|
|
58
|
-
{ open: "'", close: "'" },
|
|
59
|
-
{ open: "`", close: "`" }
|
|
60
|
-
],
|
|
61
|
-
indentationRules: {
|
|
62
|
-
increaseIndentPattern: /^.*(\bcapture\b\s+\S+|\bsource\b(?:\s+\w+)?|\bmap\b|\bappend\b\s+\S+|\bnested\b\s+\S+|\bchildren\b\s+\S+.*|\btranslate\b|\bsplit\b.*)\s*$/,
|
|
63
|
-
decreaseIndentPattern: /^.*\}.*$/
|
|
64
|
-
},
|
|
65
|
-
folding: {
|
|
66
|
-
offSide: true,
|
|
67
|
-
markers: {
|
|
68
|
-
start: /^\s*(capture|source|map|append|nested|children|translate|split)/,
|
|
69
|
-
end: /^\s*$/
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
wordPattern: /[$]?[a-zA-Z_][\w$-]*/
|
|
73
|
-
};
|
|
74
|
-
var monarchLanguage = {
|
|
75
|
-
defaultToken: "",
|
|
76
|
-
tokenPostfix: ".cdl",
|
|
77
|
-
keywords: KEYWORDS,
|
|
78
|
-
builtins: BUILTINS,
|
|
79
|
-
operators: OPERATORS,
|
|
80
|
-
symbols: /[=><!~?:&|+\-*/^%]+/,
|
|
81
|
-
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
|
|
82
|
-
tokenizer: {
|
|
83
|
-
root: [
|
|
84
|
-
{ include: "@whitespace" },
|
|
85
|
-
[/`/, { token: "string.template", next: "@templateString" }],
|
|
86
|
-
[/\$\.(?:[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)?/, "variable"],
|
|
87
|
-
[/\$previous(?:\.[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)?/, "variable.predefined"],
|
|
88
|
-
[/\$context(?:\.(?:occurred|eventSourceId))?/, "variable.predefined"],
|
|
89
|
-
[/\$env(?:\.[A-Z_][A-Z0-9_]*)?/, "variable.predefined"],
|
|
90
|
-
[/@[a-zA-Z_$][\w$]*/, "identifier.escape"],
|
|
91
|
-
[
|
|
92
|
-
/[A-Z][a-zA-Z_$][\w$]*/,
|
|
93
|
-
{
|
|
94
|
-
cases: {
|
|
95
|
-
"@keywords": "invalid",
|
|
96
|
-
"@default": "identifier"
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
],
|
|
100
|
-
[
|
|
101
|
-
/[a-z_$][\w$]*/,
|
|
102
|
-
{
|
|
103
|
-
cases: {
|
|
104
|
-
"@keywords": "keyword",
|
|
105
|
-
"@builtins": "variable.predefined",
|
|
106
|
-
"@default": "identifier"
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
],
|
|
110
|
-
[/[{}()[\]]/, "@brackets"],
|
|
111
|
-
[/=>/, "operator.arrow"],
|
|
112
|
-
[
|
|
113
|
-
/@symbols/,
|
|
114
|
-
{
|
|
115
|
-
cases: {
|
|
116
|
-
"@operators": "operator",
|
|
117
|
-
"@default": ""
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
],
|
|
121
|
-
[/\d*\.\d+([eE][-+]?\d+)?/, "number.float"],
|
|
122
|
-
[/0[xX][0-9a-fA-F]+/, "number.hex"],
|
|
123
|
-
[/\d+/, "number"],
|
|
124
|
-
[/[;,.]/, "delimiter"],
|
|
125
|
-
[/"([^"\\]|\\.)*$/, "string.invalid"],
|
|
126
|
-
[/"/, { token: "string.quote", next: "@string" }]
|
|
127
|
-
],
|
|
128
|
-
whitespace: [
|
|
129
|
-
[/[ \t\r\n]+/, ""],
|
|
130
|
-
[/#.*$/, "comment"]
|
|
131
|
-
],
|
|
132
|
-
templateString: [
|
|
133
|
-
[/\$\{/, { token: "delimiter.bracket", next: "@templateExpression" }],
|
|
134
|
-
[/[^\\`$]+/, "string.template"],
|
|
135
|
-
[/@escapes/, "string.template.escape"],
|
|
136
|
-
[/\\./, "string.template.escape.invalid"],
|
|
137
|
-
[/`/, { token: "string.template", next: "@pop" }]
|
|
138
|
-
],
|
|
139
|
-
templateExpression: [
|
|
140
|
-
[/\}/, { token: "delimiter.bracket", next: "@pop" }],
|
|
141
|
-
{ include: "@root" }
|
|
142
|
-
],
|
|
143
|
-
string: [
|
|
144
|
-
[/[^\\"]+/, "string"],
|
|
145
|
-
[/@escapes/, "string.escape"],
|
|
146
|
-
[/\\./, "string.escape.invalid"],
|
|
147
|
-
[/"/, { token: "string.quote", next: "@pop" }]
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
};
|
|
1
|
+
var languageId="cdl",KEYWORDS=["capture","source","key","map","append","when","nested","children","identified","by","api","webhook","message","route","poll","path","topic","from","to","or","and","added","removed","translate","split"],BUILTINS=["$context","$previous","$env"],OPERATORS=["=","=>","."],languageConfiguration={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:/^.*(\bcapture\b\s+\S+|\bsource\b(?:\s+\w+)?|\bmap\b|\bappend\b\s+\S+|\bnested\b\s+\S+|\bchildren\b\s+\S+.*|\btranslate\b|\bsplit\b.*)\s*$/,decreaseIndentPattern:/^.*\}.*$/},folding:{offSide:!0,markers:{start:/^\s*(capture|source|map|append|nested|children|translate|split)/,end:/^\s*$/}},wordPattern:/[$]?[a-zA-Z_][\w$-]*/},monarchLanguage={defaultToken:"",tokenPostfix:".cdl",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*(?:\.[a-zA-Z_]\w*)*)?/,"variable"],[/\$previous(?:\.[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)?/,"variable.predefined"],[/\$context(?:\.(?:occurred|eventSourceId))?/,"variable.predefined"],[/\$env(?:\.[A-Z_][A-Z0-9_]*)?/,"variable.predefined"],[/@[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"}]]}};import{languages}from"monaco-editor";var commonPropertyPaths=["id","status","firstName","lastName","fullName","address.street","address.city","lineItems","lineItems.quantity","lineNumber","quantity"],CompletionProvider=class{triggerCharacters=["."," ","=","$"];provideCompletionItems(model,position){let context=this.buildContext(model,position),suggestions=[];return context.lineNumber===1?this.addCaptureLineCompletions(suggestions,context):this.isAfterKeyword(context,"capture")?this.addCaptureNameCompletions(suggestions,context):this.isAfterKeyword(context,"source")?this.addSourceTypeCompletions(suggestions,context):this.isAfterAppendKeyword(context)?this.addAppendNameCompletions(suggestions,context):this.isAfterWhenKeyword(context)?this.addWhenCompletions(suggestions,context):this.isAfterWhenFrom(context)?this.addFromValueCompletions(suggestions,context):this.isAfterWhenTo(context)?this.addToValueCompletions(suggestions,context):this.isAfterContextPrefix(context,"$.")?this.addPathCompletions(suggestions,context,"$."):this.isAfterContextPrefix(context,"$previous.")?this.addPathCompletions(suggestions,context,"$previous."):this.isAfterContextPrefix(context,"$context.")?this.addContextCompletions(suggestions,context):this.isAfterContextPrefix(context,"$env.")?this.addEnvironmentCompletions(suggestions,context):this.isAfterAssignment(context)?this.addAssignmentValueCompletions(suggestions,context):(this.isStartOfLine(context)||this.isAfterIndent(context))&&context.indentLevel===1?this.addTopLevelStatementCompletions(suggestions,context):(this.isStartOfLine(context)||this.isAfterIndent(context))&&context.indentLevel>=2&&this.addSourceBlockCompletions(suggestions,context,this.getCurrentSourceType(model,position.lineNumber)),{suggestions}}buildContext(model,position){let textBeforeCursor=model.getLineContent(position.lineNumber).substring(0,position.column-1),word=model.getWordUntilPosition(position);return{textBeforeCursor,currentWord:word.word||"",indentLevel:this.getIndentLevel(textBeforeCursor),lineNumber:position.lineNumber,wordStartColumn:word.startColumn,wordEndColumn:word.endColumn}}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)}isAfterAppendKeyword(context){return/\bappend\s+[\w.]*$/.test(context.textBeforeCursor)}isAfterWhenKeyword(context){return/\bwhen\s+[\w.]*$/.test(context.textBeforeCursor)}isAfterWhenFrom(context){return/\bwhen\s+[\w.]+\s+from\s+[^\s]*$/.test(context.textBeforeCursor)}isAfterWhenTo(context){return/\bwhen\s+[\w.]+\s+from\s+\S+\s+to\s+[^\s]*$/.test(context.textBeforeCursor)}isAfterAssignment(context){return/=\s*([$\w.]*)$/.test(context.textBeforeCursor)}isAfterContextPrefix(context,prefix){return context.textBeforeCursor.endsWith(prefix)}addCaptureLineCompletions(suggestions,context){let trimmed=context.textBeforeCursor.trim();(trimmed===""||"capture".startsWith(trimmed))&&suggestions.push({label:"capture",kind:languages.CompletionItemKind.Keyword,insertText:"capture ",documentation:"Define a capture declaration",detail:"capture <Name>",range:this.getRangeForWord(context)}),trimmed.startsWith("capture ")&&this.addCaptureNameCompletions(suggestions,context)}addCaptureNameCompletions(suggestions,context){suggestions.push({label:"CaptureDefinition",kind:languages.CompletionItemKind.Class,insertText:"CaptureDefinition",documentation:"A descriptive name for this capture declaration",detail:"Capture name",range:this.getRangeForWord(context)})}addSourceTypeCompletions(suggestions,context){[{label:"api",detail:"source api",documentation:"Capture data by polling an HTTP API"},{label:"webhook",detail:"source webhook",documentation:"Capture data from incoming webhook requests"},{label:"message",detail:"source message",documentation:"Capture data from a message topic"}].forEach(source=>{suggestions.push({label:source.label,kind:languages.CompletionItemKind.Keyword,insertText:source.label,documentation:source.documentation,detail:source.detail,range:this.getRangeForWord(context)})})}addSourceBlockCompletions(suggestions,context,sourceType){(sourceType?{api:[{label:"api",detail:"api <ServiceName>",documentation:"References a configured External Service by name for the base URL and authentication"},{label:"route",detail:"route <path>",documentation:"Optional path appended to the External Service base URL; if omitted, the base URL is used as-is"},{label:"poll",detail:"poll <interval>",documentation:"The polling interval, for example 5m"}],webhook:[{label:"path",detail:"path <route>",documentation:"The inbound path this webhook listens on"}],message:[{label:"topic",detail:"topic <name>",documentation:"The topic or subject to subscribe to"}]}[sourceType]??[]:[]).forEach(option=>{suggestions.push({label:option.label,kind:languages.CompletionItemKind.Keyword,insertText:`${option.label} `,documentation:option.documentation,detail:option.detail,range:this.getRangeForWord(context)})})}addTopLevelStatementCompletions(suggestions,context){[{label:"key",insertText:"key ",detail:"key <property>",documentation:"Identify the captured entity"},{label:"map",insertText:"map",detail:"map",documentation:"Map captured fields into a normalized shape"},{label:"append",insertText:"append ",detail:"append <EventName>",documentation:"Append an event when a condition matches"},{label:"nested",insertText:"nested ",detail:"nested <property>",documentation:"Create a nested mapping scope"},{label:"children",insertText:"children ",detail:"children <collection> identified by <property>",documentation:"Handle child collections independently"}].forEach(statement=>{suggestions.push({label:statement.label,kind:languages.CompletionItemKind.Keyword,insertText:statement.insertText,documentation:statement.documentation,detail:statement.detail,range:this.getRangeForWord(context)})})}addAppendNameCompletions(suggestions,context){suggestions.push({label:"ItemChanged",kind:languages.CompletionItemKind.Class,insertText:"ItemChanged",documentation:"A generic event name for the appended event",detail:"Event name",range:this.getRangeForWord(context)})}addWhenCompletions(suggestions,context){[{label:"added",insertText:"added",detail:"when added",documentation:"Append when a child item was added"},{label:"removed",insertText:"removed",detail:"when removed",documentation:"Append when a child item was removed"},{label:"status",insertText:"status",detail:"when <property>",documentation:"Append when a property changed"},{label:"status transition",insertText:"status from inactive to active",detail:"when <property> from <value> to <value>",documentation:"Append when a property changed between two values"},{label:"quantity",insertText:"quantity",detail:"when <property>",documentation:"Append when a property changed"},{label:"lineNumber",insertText:"lineNumber",detail:"when <property>",documentation:"Append when a specific property changed"}].forEach(option=>{suggestions.push({label:option.label,kind:languages.CompletionItemKind.Keyword,insertText:option.insertText,documentation:option.documentation,detail:option.detail,range:this.getRangeForWord(context)})})}addFromValueCompletions(suggestions,context){[{label:"*",insertText:"*",detail:"Wildcard",documentation:"Match any previous value"},{label:"inactive",insertText:"inactive",detail:"Common value",documentation:"A common previous state value"},{label:"active",insertText:"active",detail:"Common value",documentation:"A common previous state value"},{label:"true",insertText:"true",detail:"Boolean value",documentation:"Boolean true"},{label:"false",insertText:"false",detail:"Boolean value",documentation:"Boolean false"}].forEach(option=>{suggestions.push({label:option.label,kind:languages.CompletionItemKind.Value,insertText:option.insertText,documentation:option.documentation,detail:option.detail,range:this.getRangeForWord(context)})})}addToValueCompletions(suggestions,context){["active","inactive","pending","true","false"].forEach(value=>{suggestions.push({label:value,kind:languages.CompletionItemKind.Value,insertText:value,documentation:`Common target value: ${value}`,detail:"Target value",range:this.getRangeForWord(context)})})}addAssignmentValueCompletions(suggestions,context){[{label:"$.",insertText:"$.",detail:"Current captured value",documentation:"Reference the current captured payload"},{label:"$previous.",insertText:"$previous.",detail:"Previous captured value",documentation:"Reference the previous state of the payload"},{label:"$context.occurred",insertText:"$context.occurred",detail:"Occurred timestamp",documentation:"When the capture source produced the current data"},{label:"$context.eventSourceId",insertText:"$context.eventSourceId",detail:"Event source identifier",documentation:"The resolved event source identifier for the append operation"},{label:"$env.",insertText:"$env.",detail:"Environment variable",documentation:"Read an environment variable"}].forEach(option=>{suggestions.push({label:option.label,kind:languages.CompletionItemKind.Variable,insertText:option.insertText,documentation:option.documentation,detail:option.detail,range:this.getRangeForWord(context)})})}addPathCompletions(suggestions,context,prefix){commonPropertyPaths.forEach(path=>{suggestions.push({label:path,kind:languages.CompletionItemKind.Property,insertText:`${prefix}${path}`,documentation:`Common property path: ${prefix}${path}`,detail:prefix==="$."?"Current value path":"Previous value path",range:this.getRangeForWord(context)})})}addContextCompletions(suggestions,context){[{label:"occurred",insertText:"$context.occurred",detail:"When the event occurred",documentation:"Timestamp for when the append event happened"},{label:"eventSourceId",insertText:"$context.eventSourceId",detail:"Event source identifier",documentation:"The event source identifier used for the appended event"}].forEach(option=>{suggestions.push({label:option.label,kind:languages.CompletionItemKind.Property,insertText:option.insertText,documentation:option.documentation,detail:option.detail,range:this.getRangeForWord(context)})})}addEnvironmentCompletions(suggestions,context){suggestions.push({label:"API_TOKEN",kind:languages.CompletionItemKind.Variable,insertText:"$env.API_TOKEN",documentation:"Placeholder environment variable reference",detail:"Environment variable",range:this.getRangeForWord(context)})}getCurrentSourceType(model,lineNumber){for(let index=lineNumber;index>=1;index--){let match=model.getLineContent(index).trim().match(/^source\s+(api|webhook|message)\b/);if(match)return match[1]}return null}getRangeForWord(context){return{startLineNumber:context.lineNumber,endLineNumber:context.lineNumber,startColumn:context.wordStartColumn,endColumn:context.wordEndColumn}}};var HoverProvider=class{provideHover(model,position){let token=this.getTokenAtPosition(model,position);if(!token)return null;let keywordInfo=this.getKeywordInfo(token.word);if(keywordInfo)return{contents:[{value:keywordInfo}],range:token.range};let expressionInfo=this.getExpressionInfo(token.word);return expressionInfo?{contents:[{value:expressionInfo}],range:token.range}:null}getTokenAtPosition(model,position){let tokens=[...model.getLineContent(position.lineNumber).matchAll(/\$context|\$previous|\$env|[a-zA-Z_][\w-]*/g)],column=position.column-1;for(let token of tokens){let startIndex=token.index??0,endIndex=startIndex+token[0].length;if(column>=startIndex&&column<=endIndex)return{word:token[0],range:{startLineNumber:position.lineNumber,endLineNumber:position.lineNumber,startColumn:startIndex+1,endColumn:endIndex+1}}}return null}getKeywordInfo(word){return{capture:`**capture** *<Name>*
|
|
151
2
|
|
|
152
|
-
|
|
153
|
-
import { languages } from "monaco-editor";
|
|
154
|
-
var commonPropertyPaths = [
|
|
155
|
-
"id",
|
|
156
|
-
"status",
|
|
157
|
-
"firstName",
|
|
158
|
-
"lastName",
|
|
159
|
-
"fullName",
|
|
160
|
-
"address.street",
|
|
161
|
-
"address.city",
|
|
162
|
-
"lineItems",
|
|
163
|
-
"lineItems.quantity",
|
|
164
|
-
"lineNumber",
|
|
165
|
-
"quantity"
|
|
166
|
-
];
|
|
167
|
-
var CompletionProvider = class {
|
|
168
|
-
triggerCharacters = [".", " ", "=", "$"];
|
|
169
|
-
provideCompletionItems(model, position) {
|
|
170
|
-
const context = this.buildContext(model, position);
|
|
171
|
-
const suggestions = [];
|
|
172
|
-
if (context.lineNumber === 1) {
|
|
173
|
-
this.addCaptureLineCompletions(suggestions, context);
|
|
174
|
-
} else if (this.isAfterKeyword(context, "capture")) {
|
|
175
|
-
this.addCaptureNameCompletions(suggestions, context);
|
|
176
|
-
} else if (this.isAfterKeyword(context, "source")) {
|
|
177
|
-
this.addSourceTypeCompletions(suggestions, context);
|
|
178
|
-
} else if (this.isAfterAppendKeyword(context)) {
|
|
179
|
-
this.addAppendNameCompletions(suggestions, context);
|
|
180
|
-
} else if (this.isAfterWhenKeyword(context)) {
|
|
181
|
-
this.addWhenCompletions(suggestions, context);
|
|
182
|
-
} else if (this.isAfterWhenFrom(context)) {
|
|
183
|
-
this.addFromValueCompletions(suggestions, context);
|
|
184
|
-
} else if (this.isAfterWhenTo(context)) {
|
|
185
|
-
this.addToValueCompletions(suggestions, context);
|
|
186
|
-
} else if (this.isAfterContextPrefix(context, "$.")) {
|
|
187
|
-
this.addPathCompletions(suggestions, context, "$.");
|
|
188
|
-
} else if (this.isAfterContextPrefix(context, "$previous.")) {
|
|
189
|
-
this.addPathCompletions(suggestions, context, "$previous.");
|
|
190
|
-
} else if (this.isAfterContextPrefix(context, "$context.")) {
|
|
191
|
-
this.addContextCompletions(suggestions, context);
|
|
192
|
-
} else if (this.isAfterContextPrefix(context, "$env.")) {
|
|
193
|
-
this.addEnvironmentCompletions(suggestions, context);
|
|
194
|
-
} else if (this.isAfterAssignment(context)) {
|
|
195
|
-
this.addAssignmentValueCompletions(suggestions, context);
|
|
196
|
-
} else if ((this.isStartOfLine(context) || this.isAfterIndent(context)) && context.indentLevel === 1) {
|
|
197
|
-
this.addTopLevelStatementCompletions(suggestions, context);
|
|
198
|
-
} else if ((this.isStartOfLine(context) || this.isAfterIndent(context)) && context.indentLevel >= 2) {
|
|
199
|
-
this.addSourceBlockCompletions(suggestions, context, this.getCurrentSourceType(model, position.lineNumber));
|
|
200
|
-
}
|
|
201
|
-
return { suggestions };
|
|
202
|
-
}
|
|
203
|
-
buildContext(model, position) {
|
|
204
|
-
const lineContent = model.getLineContent(position.lineNumber);
|
|
205
|
-
const textBeforeCursor = lineContent.substring(0, position.column - 1);
|
|
206
|
-
const word = model.getWordUntilPosition(position);
|
|
207
|
-
return {
|
|
208
|
-
textBeforeCursor,
|
|
209
|
-
currentWord: word.word || "",
|
|
210
|
-
indentLevel: this.getIndentLevel(textBeforeCursor),
|
|
211
|
-
lineNumber: position.lineNumber,
|
|
212
|
-
wordStartColumn: word.startColumn,
|
|
213
|
-
wordEndColumn: word.endColumn
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
getIndentLevel(text) {
|
|
217
|
-
const match = text.match(/^(\s*)/);
|
|
218
|
-
return match ? Math.floor(match[1].length / 2) : 0;
|
|
219
|
-
}
|
|
220
|
-
isStartOfLine(context) {
|
|
221
|
-
return context.textBeforeCursor.trim() === "";
|
|
222
|
-
}
|
|
223
|
-
isAfterIndent(context) {
|
|
224
|
-
return /^\s+$/.test(context.textBeforeCursor);
|
|
225
|
-
}
|
|
226
|
-
isAfterKeyword(context, keyword) {
|
|
227
|
-
const pattern = new RegExp(`\\b${keyword}\\s+\\w*$`);
|
|
228
|
-
return pattern.test(context.textBeforeCursor);
|
|
229
|
-
}
|
|
230
|
-
isAfterAppendKeyword(context) {
|
|
231
|
-
return /\bappend\s+[\w.]*$/.test(context.textBeforeCursor);
|
|
232
|
-
}
|
|
233
|
-
isAfterWhenKeyword(context) {
|
|
234
|
-
return /\bwhen\s+[\w.]*$/.test(context.textBeforeCursor);
|
|
235
|
-
}
|
|
236
|
-
isAfterWhenFrom(context) {
|
|
237
|
-
return /\bwhen\s+[\w.]+\s+from\s+[^\s]*$/.test(context.textBeforeCursor);
|
|
238
|
-
}
|
|
239
|
-
isAfterWhenTo(context) {
|
|
240
|
-
return /\bwhen\s+[\w.]+\s+from\s+\S+\s+to\s+[^\s]*$/.test(context.textBeforeCursor);
|
|
241
|
-
}
|
|
242
|
-
isAfterAssignment(context) {
|
|
243
|
-
return /=\s*([$\w.]*)$/.test(context.textBeforeCursor);
|
|
244
|
-
}
|
|
245
|
-
isAfterContextPrefix(context, prefix) {
|
|
246
|
-
return context.textBeforeCursor.endsWith(prefix);
|
|
247
|
-
}
|
|
248
|
-
addCaptureLineCompletions(suggestions, context) {
|
|
249
|
-
const trimmed = context.textBeforeCursor.trim();
|
|
250
|
-
if (trimmed === "" || "capture".startsWith(trimmed)) {
|
|
251
|
-
suggestions.push({
|
|
252
|
-
label: "capture",
|
|
253
|
-
kind: languages.CompletionItemKind.Keyword,
|
|
254
|
-
insertText: "capture ",
|
|
255
|
-
documentation: "Define a capture declaration",
|
|
256
|
-
detail: "capture <Name>",
|
|
257
|
-
range: this.getRangeForWord(context)
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
if (trimmed.startsWith("capture ")) {
|
|
261
|
-
this.addCaptureNameCompletions(suggestions, context);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
addCaptureNameCompletions(suggestions, context) {
|
|
265
|
-
suggestions.push({
|
|
266
|
-
label: "CaptureDefinition",
|
|
267
|
-
kind: languages.CompletionItemKind.Class,
|
|
268
|
-
insertText: "CaptureDefinition",
|
|
269
|
-
documentation: "A descriptive name for this capture declaration",
|
|
270
|
-
detail: "Capture name",
|
|
271
|
-
range: this.getRangeForWord(context)
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
addSourceTypeCompletions(suggestions, context) {
|
|
275
|
-
[
|
|
276
|
-
{ label: "api", detail: "source api", documentation: "Capture data by polling an HTTP API" },
|
|
277
|
-
{ label: "webhook", detail: "source webhook", documentation: "Capture data from incoming webhook requests" },
|
|
278
|
-
{ label: "message", detail: "source message", documentation: "Capture data from a message topic" }
|
|
279
|
-
].forEach((source) => {
|
|
280
|
-
suggestions.push({
|
|
281
|
-
label: source.label,
|
|
282
|
-
kind: languages.CompletionItemKind.Keyword,
|
|
283
|
-
insertText: source.label,
|
|
284
|
-
documentation: source.documentation,
|
|
285
|
-
detail: source.detail,
|
|
286
|
-
range: this.getRangeForWord(context)
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
// Per source type — no `auth`/`bearer`/`url`: an API source references a named
|
|
291
|
-
// External Service (`api <ServiceName>`) for base URL and auth; a webhook source's
|
|
292
|
-
// authentication is configured on the source builder, not in CDL text.
|
|
293
|
-
addSourceBlockCompletions(suggestions, context, sourceType) {
|
|
294
|
-
const options = {
|
|
295
|
-
api: [
|
|
296
|
-
{ label: "api", detail: "api <ServiceName>", documentation: "References a configured External Service by name for the base URL and authentication" },
|
|
297
|
-
{ label: "route", detail: "route <path>", documentation: "Optional path appended to the External Service base URL; if omitted, the base URL is used as-is" },
|
|
298
|
-
{ label: "poll", detail: "poll <interval>", documentation: "The polling interval, for example 5m" }
|
|
299
|
-
],
|
|
300
|
-
webhook: [
|
|
301
|
-
{ label: "path", detail: "path <route>", documentation: "The inbound path this webhook listens on" }
|
|
302
|
-
],
|
|
303
|
-
message: [
|
|
304
|
-
{ label: "topic", detail: "topic <name>", documentation: "The topic or subject to subscribe to" }
|
|
305
|
-
]
|
|
306
|
-
};
|
|
307
|
-
(sourceType ? options[sourceType] ?? [] : []).forEach((option) => {
|
|
308
|
-
suggestions.push({
|
|
309
|
-
label: option.label,
|
|
310
|
-
kind: languages.CompletionItemKind.Keyword,
|
|
311
|
-
insertText: `${option.label} `,
|
|
312
|
-
documentation: option.documentation,
|
|
313
|
-
detail: option.detail,
|
|
314
|
-
range: this.getRangeForWord(context)
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
addTopLevelStatementCompletions(suggestions, context) {
|
|
319
|
-
[
|
|
320
|
-
{ label: "key", insertText: "key ", detail: "key <property>", documentation: "Identify the captured entity" },
|
|
321
|
-
{ label: "map", insertText: "map", detail: "map", documentation: "Map captured fields into a normalized shape" },
|
|
322
|
-
{ label: "append", insertText: "append ", detail: "append <EventName>", documentation: "Append an event when a condition matches" },
|
|
323
|
-
{ label: "nested", insertText: "nested ", detail: "nested <property>", documentation: "Create a nested mapping scope" },
|
|
324
|
-
{ label: "children", insertText: "children ", detail: "children <collection> identified by <property>", documentation: "Handle child collections independently" }
|
|
325
|
-
].forEach((statement) => {
|
|
326
|
-
suggestions.push({
|
|
327
|
-
label: statement.label,
|
|
328
|
-
kind: languages.CompletionItemKind.Keyword,
|
|
329
|
-
insertText: statement.insertText,
|
|
330
|
-
documentation: statement.documentation,
|
|
331
|
-
detail: statement.detail,
|
|
332
|
-
range: this.getRangeForWord(context)
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
addAppendNameCompletions(suggestions, context) {
|
|
337
|
-
suggestions.push({
|
|
338
|
-
label: "ItemChanged",
|
|
339
|
-
kind: languages.CompletionItemKind.Class,
|
|
340
|
-
insertText: "ItemChanged",
|
|
341
|
-
documentation: "A generic event name for the appended event",
|
|
342
|
-
detail: "Event name",
|
|
343
|
-
range: this.getRangeForWord(context)
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
addWhenCompletions(suggestions, context) {
|
|
347
|
-
[
|
|
348
|
-
{ label: "added", insertText: "added", detail: "when added", documentation: "Append when a child item was added" },
|
|
349
|
-
{ label: "removed", insertText: "removed", detail: "when removed", documentation: "Append when a child item was removed" },
|
|
350
|
-
{ label: "status", insertText: "status", detail: "when <property>", documentation: "Append when a property changed" },
|
|
351
|
-
{ label: "status transition", insertText: "status from inactive to active", detail: "when <property> from <value> to <value>", documentation: "Append when a property changed between two values" },
|
|
352
|
-
{ label: "quantity", insertText: "quantity", detail: "when <property>", documentation: "Append when a property changed" },
|
|
353
|
-
{ label: "lineNumber", insertText: "lineNumber", detail: "when <property>", documentation: "Append when a specific property changed" }
|
|
354
|
-
].forEach((option) => {
|
|
355
|
-
suggestions.push({
|
|
356
|
-
label: option.label,
|
|
357
|
-
kind: languages.CompletionItemKind.Keyword,
|
|
358
|
-
insertText: option.insertText,
|
|
359
|
-
documentation: option.documentation,
|
|
360
|
-
detail: option.detail,
|
|
361
|
-
range: this.getRangeForWord(context)
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
addFromValueCompletions(suggestions, context) {
|
|
366
|
-
[
|
|
367
|
-
{ label: "*", insertText: "*", detail: "Wildcard", documentation: "Match any previous value" },
|
|
368
|
-
{ label: "inactive", insertText: "inactive", detail: "Common value", documentation: "A common previous state value" },
|
|
369
|
-
{ label: "active", insertText: "active", detail: "Common value", documentation: "A common previous state value" },
|
|
370
|
-
{ label: "true", insertText: "true", detail: "Boolean value", documentation: "Boolean true" },
|
|
371
|
-
{ label: "false", insertText: "false", detail: "Boolean value", documentation: "Boolean false" }
|
|
372
|
-
].forEach((option) => {
|
|
373
|
-
suggestions.push({
|
|
374
|
-
label: option.label,
|
|
375
|
-
kind: languages.CompletionItemKind.Value,
|
|
376
|
-
insertText: option.insertText,
|
|
377
|
-
documentation: option.documentation,
|
|
378
|
-
detail: option.detail,
|
|
379
|
-
range: this.getRangeForWord(context)
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
addToValueCompletions(suggestions, context) {
|
|
384
|
-
["active", "inactive", "pending", "true", "false"].forEach((value) => {
|
|
385
|
-
suggestions.push({
|
|
386
|
-
label: value,
|
|
387
|
-
kind: languages.CompletionItemKind.Value,
|
|
388
|
-
insertText: value,
|
|
389
|
-
documentation: `Common target value: ${value}`,
|
|
390
|
-
detail: "Target value",
|
|
391
|
-
range: this.getRangeForWord(context)
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
addAssignmentValueCompletions(suggestions, context) {
|
|
396
|
-
[
|
|
397
|
-
{ label: "$.", insertText: "$.", detail: "Current captured value", documentation: "Reference the current captured payload" },
|
|
398
|
-
{ label: "$previous.", insertText: "$previous.", detail: "Previous captured value", documentation: "Reference the previous state of the payload" },
|
|
399
|
-
{ label: "$context.occurred", insertText: "$context.occurred", detail: "Occurred timestamp", documentation: "When the capture source produced the current data" },
|
|
400
|
-
{ label: "$context.eventSourceId", insertText: "$context.eventSourceId", detail: "Event source identifier", documentation: "The resolved event source identifier for the append operation" },
|
|
401
|
-
{ label: "$env.", insertText: "$env.", detail: "Environment variable", documentation: "Read an environment variable" }
|
|
402
|
-
].forEach((option) => {
|
|
403
|
-
suggestions.push({
|
|
404
|
-
label: option.label,
|
|
405
|
-
kind: languages.CompletionItemKind.Variable,
|
|
406
|
-
insertText: option.insertText,
|
|
407
|
-
documentation: option.documentation,
|
|
408
|
-
detail: option.detail,
|
|
409
|
-
range: this.getRangeForWord(context)
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
addPathCompletions(suggestions, context, prefix) {
|
|
414
|
-
commonPropertyPaths.forEach((path) => {
|
|
415
|
-
suggestions.push({
|
|
416
|
-
label: path,
|
|
417
|
-
kind: languages.CompletionItemKind.Property,
|
|
418
|
-
insertText: `${prefix}${path}`,
|
|
419
|
-
documentation: `Common property path: ${prefix}${path}`,
|
|
420
|
-
detail: prefix === "$." ? "Current value path" : "Previous value path",
|
|
421
|
-
range: this.getRangeForWord(context)
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
addContextCompletions(suggestions, context) {
|
|
426
|
-
[
|
|
427
|
-
{ label: "occurred", insertText: "$context.occurred", detail: "When the event occurred", documentation: "Timestamp for when the append event happened" },
|
|
428
|
-
{ label: "eventSourceId", insertText: "$context.eventSourceId", detail: "Event source identifier", documentation: "The event source identifier used for the appended event" }
|
|
429
|
-
].forEach((option) => {
|
|
430
|
-
suggestions.push({
|
|
431
|
-
label: option.label,
|
|
432
|
-
kind: languages.CompletionItemKind.Property,
|
|
433
|
-
insertText: option.insertText,
|
|
434
|
-
documentation: option.documentation,
|
|
435
|
-
detail: option.detail,
|
|
436
|
-
range: this.getRangeForWord(context)
|
|
437
|
-
});
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
addEnvironmentCompletions(suggestions, context) {
|
|
441
|
-
suggestions.push({
|
|
442
|
-
label: "API_TOKEN",
|
|
443
|
-
kind: languages.CompletionItemKind.Variable,
|
|
444
|
-
insertText: "$env.API_TOKEN",
|
|
445
|
-
documentation: "Placeholder environment variable reference",
|
|
446
|
-
detail: "Environment variable",
|
|
447
|
-
range: this.getRangeForWord(context)
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
getCurrentSourceType(model, lineNumber) {
|
|
451
|
-
for (let index = lineNumber; index >= 1; index--) {
|
|
452
|
-
const line = model.getLineContent(index).trim();
|
|
453
|
-
const match = line.match(/^source\s+(api|webhook|message)\b/);
|
|
454
|
-
if (match) {
|
|
455
|
-
return match[1];
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
getRangeForWord(context) {
|
|
461
|
-
return {
|
|
462
|
-
startLineNumber: context.lineNumber,
|
|
463
|
-
endLineNumber: context.lineNumber,
|
|
464
|
-
startColumn: context.wordStartColumn,
|
|
465
|
-
endColumn: context.wordEndColumn
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
};
|
|
3
|
+
Declares a capture and gives it a unique name.`,source:`**source** *<type>*
|
|
469
4
|
|
|
470
|
-
|
|
471
|
-
var HoverProvider = class {
|
|
472
|
-
provideHover(model, position) {
|
|
473
|
-
const token = this.getTokenAtPosition(model, position);
|
|
474
|
-
if (!token) {
|
|
475
|
-
return null;
|
|
476
|
-
}
|
|
477
|
-
const keywordInfo = this.getKeywordInfo(token.word);
|
|
478
|
-
if (keywordInfo) {
|
|
479
|
-
return {
|
|
480
|
-
contents: [{ value: keywordInfo }],
|
|
481
|
-
range: token.range
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
const expressionInfo = this.getExpressionInfo(token.word);
|
|
485
|
-
if (expressionInfo) {
|
|
486
|
-
return {
|
|
487
|
-
contents: [{ value: expressionInfo }],
|
|
488
|
-
range: token.range
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
return null;
|
|
492
|
-
}
|
|
493
|
-
getTokenAtPosition(model, position) {
|
|
494
|
-
const lineContent = model.getLineContent(position.lineNumber);
|
|
495
|
-
const tokens = [...lineContent.matchAll(/\$context|\$previous|\$env|[a-zA-Z_][\w-]*/g)];
|
|
496
|
-
const column = position.column - 1;
|
|
497
|
-
for (const token of tokens) {
|
|
498
|
-
const startIndex = token.index ?? 0;
|
|
499
|
-
const endIndex = startIndex + token[0].length;
|
|
500
|
-
if (column >= startIndex && column <= endIndex) {
|
|
501
|
-
return {
|
|
502
|
-
word: token[0],
|
|
503
|
-
range: {
|
|
504
|
-
startLineNumber: position.lineNumber,
|
|
505
|
-
endLineNumber: position.lineNumber,
|
|
506
|
-
startColumn: startIndex + 1,
|
|
507
|
-
endColumn: endIndex + 1
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
return null;
|
|
513
|
-
}
|
|
514
|
-
// No `auth`/`bearer`/`url` — removed with the grammar. `api`, `route`, `path`, and
|
|
515
|
-
// `topic` reflect the current source-property meanings (see grammar.md).
|
|
516
|
-
getKeywordInfo(word) {
|
|
517
|
-
const keywords = {
|
|
518
|
-
capture: "**capture** *<Name>*\n\nDeclares a capture and gives it a unique name.",
|
|
519
|
-
source: "**source** *<type>*\n\nDefines where the capture reads input from.",
|
|
520
|
-
key: "**key** *<property>*\n\nSelects the property used to identify each captured item.",
|
|
521
|
-
map: "**map**\n\nMaps source fields into a normalized shape for later append blocks.",
|
|
522
|
-
append: "**append** *<EventName>*\n\nDeclares an event to append when the `when` clause matches.",
|
|
523
|
-
when: "**when** *<condition>*\n\nSpecifies when an append block should fire.",
|
|
524
|
-
nested: "**nested** *<property>*\n\nCreates a nested mapping scope for an object property.",
|
|
525
|
-
children: "**children** *<collection>* **identified by** *<property>*\n\nCreates a scope for child collection items.",
|
|
526
|
-
identified: "**identified**\n\nUsed with `children` to declare how child items are identified.",
|
|
527
|
-
by: "**by**\n\nUsed in `children ... identified by`, `split ... by`, and similar clauses.",
|
|
528
|
-
api: "**api**\n\nAs a source type (`source api`): polls an HTTP API for changes.\n\nAs a source property (`api <ServiceName>`): references a configured External Service by name for the base URL and authentication.",
|
|
529
|
-
webhook: "**webhook**\n\nA source type for receiving webhook payloads.",
|
|
530
|
-
message: "**message**\n\nA source type for consuming messages from a topic.",
|
|
531
|
-
route: "**route** *<path>*\n\nOptional path appended to an API source's External Service base URL. If omitted, the base URL is used as-is.",
|
|
532
|
-
poll: "**poll** *<interval>*\n\nSets the polling interval for an API source.",
|
|
533
|
-
path: "**path** *<route>*\n\nThe inbound path a webhook source listens on.",
|
|
534
|
-
topic: "**topic** *<name>*\n\nConfigures the topic for a message source.",
|
|
535
|
-
from: "**from** *<value>*\n\nUsed in a `when` clause to match the previous value.",
|
|
536
|
-
to: "**to** *<value>*\n\nUsed in a `when` clause to match the new value.",
|
|
537
|
-
or: "**or**\n\nCombines multiple `when` conditions.",
|
|
538
|
-
and: "**and**\n\nCombines multiple `when` conditions that must all match.",
|
|
539
|
-
added: "**added**\n\nMatches when a child item was added.",
|
|
540
|
-
removed: "**removed**\n\nMatches when a child item was removed.",
|
|
541
|
-
translate: "**translate**\n\nMaps source values to new values inside a `map` block.",
|
|
542
|
-
split: "**split** *<value>* **by** *<separator>*\n\nSplits a string into multiple mapped fields."
|
|
543
|
-
};
|
|
544
|
-
return keywords[word] || null;
|
|
545
|
-
}
|
|
546
|
-
getExpressionInfo(word) {
|
|
547
|
-
const expressions = {
|
|
548
|
-
"$context": "**$context**\n\nCapture execution context.\n\n**Properties:**\n- `occurred` - When the current event should be considered to have occurred\n- `eventSourceId` - The resolved event source identifier",
|
|
549
|
-
"$previous": "**$previous**\n\nThe previous state for the captured item. Use dot notation such as `$previous.status`.",
|
|
550
|
-
"$env": "**$env**\n\nEnvironment variables. Use dot notation such as `$env.API_TOKEN`."
|
|
551
|
-
};
|
|
552
|
-
return expressions[word] || null;
|
|
553
|
-
}
|
|
554
|
-
};
|
|
5
|
+
Defines where the capture reads input from.`,key:`**key** *<property>*
|
|
555
6
|
|
|
556
|
-
|
|
557
|
-
var Validator = class {
|
|
558
|
-
validate(lines) {
|
|
559
|
-
const issues = [];
|
|
560
|
-
let firstNonEmptyLineIndex = -1;
|
|
561
|
-
let firstLine = "";
|
|
562
|
-
for (let index = 0; index < lines.length; index++) {
|
|
563
|
-
const trimmed = lines[index].trim();
|
|
564
|
-
if (trimmed && !trimmed.startsWith("#")) {
|
|
565
|
-
firstNonEmptyLineIndex = index;
|
|
566
|
-
firstLine = trimmed;
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
if (!firstLine) {
|
|
571
|
-
return issues;
|
|
572
|
-
}
|
|
573
|
-
const captureMatch = firstLine.match(/^capture\s+([\w.]+)\s*$/);
|
|
574
|
-
if (!captureMatch) {
|
|
575
|
-
issues.push(this.error(firstNonEmptyLineIndex, 1, firstLine.length + 1, 'Capture definition must start with "capture <Name>"'));
|
|
576
|
-
return issues;
|
|
577
|
-
}
|
|
578
|
-
const meaningfulLines = lines.map((line, index) => ({
|
|
579
|
-
line,
|
|
580
|
-
trimmed: line.trim(),
|
|
581
|
-
lineNumber: index,
|
|
582
|
-
indent: line.search(/\S/)
|
|
583
|
-
})).filter((entry) => entry.trimmed && !entry.trimmed.startsWith("#"));
|
|
584
|
-
const hasSource = meaningfulLines.some((entry) => entry.trimmed.startsWith("source "));
|
|
585
|
-
if (!hasSource) {
|
|
586
|
-
issues.push(this.error(firstNonEmptyLineIndex, 1, firstLine.length + 1, 'Capture definition must include a "source" block'));
|
|
587
|
-
}
|
|
588
|
-
const hasKey = meaningfulLines.some((entry) => entry.trimmed.startsWith("key "));
|
|
589
|
-
if (!hasKey) {
|
|
590
|
-
issues.push(this.error(firstNonEmptyLineIndex, 1, firstLine.length + 1, 'Capture definition must include a "key" declaration'));
|
|
591
|
-
}
|
|
592
|
-
for (let index = 0; index < meaningfulLines.length; index++) {
|
|
593
|
-
const current = meaningfulLines[index];
|
|
594
|
-
if (!current.trimmed.startsWith("append ")) {
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
let hasWhenClause = false;
|
|
598
|
-
for (let next = index + 1; next < meaningfulLines.length; next++) {
|
|
599
|
-
const candidate = meaningfulLines[next];
|
|
600
|
-
if (candidate.indent <= current.indent) {
|
|
601
|
-
break;
|
|
602
|
-
}
|
|
603
|
-
if (candidate.trimmed.startsWith("when ")) {
|
|
604
|
-
hasWhenClause = true;
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
if (!hasWhenClause) {
|
|
609
|
-
const eventName = current.trimmed.substring("append ".length).trim() || "unnamed append block";
|
|
610
|
-
const startColumn = current.line.indexOf(eventName) + 1;
|
|
611
|
-
issues.push(this.error(
|
|
612
|
-
current.lineNumber,
|
|
613
|
-
startColumn > 0 ? startColumn : 1,
|
|
614
|
-
startColumn > 0 ? startColumn + eventName.length : current.line.length + 1,
|
|
615
|
-
`Append block '${eventName}' must include a "when" clause`
|
|
616
|
-
));
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
return issues;
|
|
620
|
-
}
|
|
621
|
-
error(line, startColumn, endColumn, message) {
|
|
622
|
-
return { severity: "error", line, startColumn, endColumn, message };
|
|
623
|
-
}
|
|
624
|
-
};
|
|
7
|
+
Selects the property used to identify each captured item.`,map:`**map**
|
|
625
8
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
disposables.push(monaco.editor.onDidCreateModel((model) => {
|
|
658
|
-
if (model.getLanguageId() !== languageId) {
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
validateModel(model);
|
|
662
|
-
disposables.push(model.onDidChangeContent(() => validateModel(model)));
|
|
663
|
-
}));
|
|
664
|
-
monaco.editor.getModels().forEach((model) => validateModel(model));
|
|
665
|
-
const dispose = () => {
|
|
666
|
-
disposables.forEach((disposable) => disposable.dispose());
|
|
667
|
-
disposables.length = 0;
|
|
668
|
-
disposersByMonaco.delete(monaco);
|
|
669
|
-
};
|
|
670
|
-
disposersByMonaco.set(monaco, dispose);
|
|
671
|
-
return { dispose };
|
|
672
|
-
}
|
|
673
|
-
export {
|
|
674
|
-
languageId,
|
|
675
|
-
registerCaptureLanguage
|
|
676
|
-
};
|
|
9
|
+
Maps source fields into a normalized shape for later append blocks.`,append:"**append** *<EventName>*\n\nDeclares an event to append when the `when` clause matches.",when:`**when** *<condition>*
|
|
10
|
+
|
|
11
|
+
Specifies when an append block should fire.`,nested:`**nested** *<property>*
|
|
12
|
+
|
|
13
|
+
Creates a nested mapping scope for an object property.`,children:`**children** *<collection>* **identified by** *<property>*
|
|
14
|
+
|
|
15
|
+
Creates a scope for child collection items.`,identified:"**identified**\n\nUsed with `children` to declare how child items are identified.",by:"**by**\n\nUsed in `children ... identified by`, `split ... by`, and similar clauses.",api:"**api**\n\nAs a source type (`source api`): polls an HTTP API for changes.\n\nAs a source property (`api <ServiceName>`): references a configured External Service by name for the base URL and authentication.",webhook:`**webhook**
|
|
16
|
+
|
|
17
|
+
A source type for receiving webhook payloads.`,message:`**message**
|
|
18
|
+
|
|
19
|
+
A source type for consuming messages from a topic.`,route:`**route** *<path>*
|
|
20
|
+
|
|
21
|
+
Optional path appended to an API source's External Service base URL. If omitted, the base URL is used as-is.`,poll:`**poll** *<interval>*
|
|
22
|
+
|
|
23
|
+
Sets the polling interval for an API source.`,path:`**path** *<route>*
|
|
24
|
+
|
|
25
|
+
The inbound path a webhook source listens on.`,topic:`**topic** *<name>*
|
|
26
|
+
|
|
27
|
+
Configures the topic for a message source.`,from:"**from** *<value>*\n\nUsed in a `when` clause to match the previous value.",to:"**to** *<value>*\n\nUsed in a `when` clause to match the new value.",or:"**or**\n\nCombines multiple `when` conditions.",and:"**and**\n\nCombines multiple `when` conditions that must all match.",added:`**added**
|
|
28
|
+
|
|
29
|
+
Matches when a child item was added.`,removed:`**removed**
|
|
30
|
+
|
|
31
|
+
Matches when a child item was removed.`,translate:"**translate**\n\nMaps source values to new values inside a `map` block.",split:`**split** *<value>* **by** *<separator>*
|
|
32
|
+
|
|
33
|
+
Splits a string into multiple mapped fields.`}[word]||null}getExpressionInfo(word){return{$context:`**$context**
|
|
34
|
+
|
|
35
|
+
Capture execution context.
|
|
36
|
+
|
|
37
|
+
**Properties:**
|
|
38
|
+
- \`occurred\` - When the current event should be considered to have occurred
|
|
39
|
+
- \`eventSourceId\` - The resolved event source identifier`,$previous:"**$previous**\n\nThe previous state for the captured item. Use dot notation such as `$previous.status`.",$env:"**$env**\n\nEnvironment variables. Use dot notation such as `$env.API_TOKEN`."}[word]||null}};var Validator=class{validate(lines){let issues=[],firstNonEmptyLineIndex=-1,firstLine="";for(let index=0;index<lines.length;index++){let trimmed=lines[index].trim();if(trimmed&&!trimmed.startsWith("#")){firstNonEmptyLineIndex=index,firstLine=trimmed;break}}if(!firstLine)return issues;if(!firstLine.match(/^capture\s+([\w.]+)\s*$/))return issues.push(this.error(firstNonEmptyLineIndex,1,firstLine.length+1,'Capture definition must start with "capture <Name>"')),issues;let meaningfulLines=lines.map((line,index)=>({line,trimmed:line.trim(),lineNumber:index,indent:line.search(/\S/)})).filter(entry=>entry.trimmed&&!entry.trimmed.startsWith("#"));meaningfulLines.some(entry=>entry.trimmed.startsWith("source "))||issues.push(this.error(firstNonEmptyLineIndex,1,firstLine.length+1,'Capture definition must include a "source" block')),meaningfulLines.some(entry=>entry.trimmed.startsWith("key "))||issues.push(this.error(firstNonEmptyLineIndex,1,firstLine.length+1,'Capture definition must include a "key" declaration'));for(let index=0;index<meaningfulLines.length;index++){let current=meaningfulLines[index];if(!current.trimmed.startsWith("append "))continue;let hasWhenClause=!1;for(let next=index+1;next<meaningfulLines.length;next++){let candidate=meaningfulLines[next];if(candidate.indent<=current.indent)break;if(candidate.trimmed.startsWith("when ")){hasWhenClause=!0;break}}if(!hasWhenClause){let eventName=current.trimmed.substring(7).trim()||"unnamed append block",startColumn=current.line.indexOf(eventName)+1;issues.push(this.error(current.lineNumber,startColumn>0?startColumn:1,startColumn>0?startColumn+eventName.length:current.line.length+1,`Append block '${eventName}' must include a "when" clause`))}}return issues}error(line,startColumn,endColumn,message){return{severity:"error",line,startColumn,endColumn,message}}};var markerOwner="cdl-validator",disposersByMonaco=new Map;function toMarkers(monaco,validator,model){return validator.validate(model.getLinesContent()).map(issue=>({severity:issue.severity==="error"?monaco.MarkerSeverity.Error:monaco.MarkerSeverity.Warning,message:issue.message,startLineNumber:issue.line+1,startColumn:issue.startColumn,endLineNumber:issue.line+1,endColumn:issue.endColumn}))}function registerCaptureLanguage(monaco){let existing=disposersByMonaco.get(monaco);if(existing)return{dispose:existing};monaco.languages.register({id:"cdl"}),monaco.languages.setLanguageConfiguration("cdl",languageConfiguration),monaco.languages.setMonarchTokensProvider("cdl",monarchLanguage);let validator=new Validator,disposables=[];disposables.push(monaco.languages.registerCompletionItemProvider("cdl",new CompletionProvider)),disposables.push(monaco.languages.registerHoverProvider("cdl",new HoverProvider));let validateModel=model=>{model.isDisposed()||model.getLanguageId()!=="cdl"||monaco.editor.setModelMarkers(model,markerOwner,toMarkers(monaco,validator,model))};disposables.push(monaco.editor.onDidCreateModel(model=>{model.getLanguageId()==="cdl"&&(validateModel(model),disposables.push(model.onDidChangeContent(()=>validateModel(model))))})),monaco.editor.getModels().forEach(model=>validateModel(model));let dispose=()=>{disposables.forEach(disposable=>disposable.dispose()),disposables.length=0,disposersByMonaco.delete(monaco)};return disposersByMonaco.set(monaco,dispose),{dispose}}export{languageId,registerCaptureLanguage};
|
|
677
40
|
//# sourceMappingURL=index.js.map
|