graphqlsp
Version:
https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin
2 lines (1 loc) • 7.17 kB
JavaScript
import e from"typescript/lib/tsserverlibrary";import{isTaggedTemplateExpression as t,isNoSubstitutionTemplateLiteral as n,isIdentifier as r,isAsExpression as i,isTemplateExpression as o,isImportTypeNode as a,isToken as s,ScriptElementKind as c}from"typescript";import{onlineParser as l,CharacterStream as p,getDiagnostics as g,getAutocompleteSuggestions as f,getHoverInformation as u}from"graphql-language-service";import{buildClientSchema as m,buildSchema as d,parse as h,printSchema as S,Kind as y}from"graphql";import x from"fs";import v from"path";import{codegen as N}from"@graphql-codegen/core";import*as T from"@graphql-codegen/typescript";import*as k from"@graphql-codegen/typescript-operations";import*as O from"@graphql-codegen/typed-document-node";class E{constructor(e,t){this.line=e,this.character=t}setLine(e){this.line=e}setCharacter(e){this.character=e}lessThanOrEqualTo(e){return this.line<e.line||this.line===e.line&&this.character<=e.character}}const I=(e,t)=>{const n=e.getText().slice(1,-1).split("\n"),r=l(),i=r.startState();let o,a=e.pos+1;for(let e=0;e<n.length;e++){const s=a,c=new p(n[e]);for(;!c.eol();){const n=r.token(c,i),a=c.current();if(a&&s+c.getStartOfToken()<=t&&s+c.getCurrentPosition()>=t){o={line:e,start:c.getStartOfToken()+1,end:c.getCurrentPosition(),string:a,state:i,tokenKind:n};break}}a+=n[e].length+1}return o};function F(t,n){return function t(r){if(n>=r.getStart()&&n<r.getEnd())return e.forEachChild(r,t)||r}(t)}function b(e,t){const n=e.languageService.getProgram();if(n)return n.getSourceFile(t)||void 0}function j(o,a,s){let c=o.template.getText().slice(1,-1);return n(o.template)||0===o.template.templateSpans.length||o.template.templateSpans.forEach((n=>{if(r(n.expression)){const r=s.languageService.getDefinitionAtPosition(a,n.expression.getStart());if(!r)return;const o=r[0],l=b(s,o.fileName);if(!l)return;const p=F(l,o.textSpan.start);if(!p||!p.parent)return;const g=p.parent;if(e.isVariableDeclaration(g))if(g.initializer&&t(g.initializer)){const e=j(g.initializer,o.fileName,s);c=c.replace("${"+n.expression.escapedText+"}",e)}else if(g.initializer&&i(g.initializer)&&t(g.initializer.expression)){const e=j(g.initializer.expression,o.fileName,s);c=c.replace("${"+n.expression.escapedText+"}",e)}}})),c}function C(i){const l=e=>i.project.projectService.logger.info(`[ts-graphql-plugin] ${e}`);if(l("config: "+JSON.stringify(i.config)),!i.config.schema)throw new Error("Please provide a GraphQL Schema!");i.project.projectService.logger.info("Setting up the GraphQL Plugin");const p=i.config.template||"gql",C=i.config.scalars||{},P=function(e){const t=Object.create(null);for(let n of Object.keys(e.languageService)){const r=e.languageService[n];t[n]=(...t)=>r.apply(e.languageService,t)}return t}(i),A=((e,t)=>{const n={current:null},r=t.endsWith("json"),i=v.resolve(v.dirname(e),t),o=x.readFileSync(i,"utf-8");return x.watchFile(i,(()=>{const e=x.readFileSync(i,"utf-8");return r?m(JSON.parse(e)):d(e),n.current=r?m(JSON.parse(e)):d(e),n})),n.current=r?m(JSON.parse(o)):d(o),n})(i.project.getProjectName(),i.config.schema);return P.getSemanticDiagnostics=r=>{const s=i.languageService.getSemanticDiagnostics(r),c=b(i,r);if(!c)return s;const l=function(r){const i=[];return function r(o){t(o)||n(o)?i.push(o):e.forEachChild(o,r)}(r),i}(c),f=l.map((e=>{if(n(e)||o(e)){if(!t(e.parent))return;e=e.parent}return j(e,r,i)})),u=l.map((e=>{let a=e;if(n(a)||o(a)){if(!t(a.parent))return;a=a.parent}const s=j(a,r,i),c=s.split("\n");let l=a.pos+(p.length+1);const f=g(s,A.current).map((e=>{const{start:t,end:n}=e.range;let r=l+t.line;for(let e=0;e<=t.line;e++)r+=e===t.line?t.character:c[e].length;let i=l+n.line;for(let e=0;e<=n.line;e++)i+=e===n.line?n.character:c[e].length;return{...e,start:r+1,length:i-r}})),u=h(s);if(u.definitions.some((e=>e.kind===y.OPERATION_DEFINITION))){const t=u.definitions.find((e=>e.kind===y.OPERATION_DEFINITION));t.name||f.push({message:"Operation needs a name for types to be generated.",start:a.pos,length:e.getText().length,range:{},severity:2})}return f})).flat().filter(Boolean).map((t=>({file:c,length:t.length,start:t.start,category:2===t.severity?e.DiagnosticCategory.Warning:e.DiagnosticCategory.Error,code:51001,messageText:t.message.split("\n")[0]})));if(!u.length)try{const e=c.fileName.split("/"),t=e[e.length-1].split(".");if(t[t.length-1]="generated.ts",e[e.length-1]=t.join("."),x.readFileSync(r,"utf-8")!==c.getFullText())return[...u,...s];(async(e,t,n,r)=>{if(!e)return;const i={documents:[{location:"operation.graphql",document:h(n)}],config:{scalars:r,enumsAsTypes:!0,dedupeOperationSuffix:!0,dedupeFragments:!0},filename:t,schema:h(S(e)),plugins:[{typescript:{}},{"typescript-operations":{}},{"typed-document-node":{}}],pluginMap:{typescript:T,"typescript-operations":k,"typed-document-node":O}},o=await N(i);x.writeFile(v.join(t),o,"utf8",(e=>{console.error(e)}))})(A.current,e.join("/"),f.join("\n"),C).then((()=>{l.forEach(((e,n)=>{var o;const s=h(f[n]||""),l=s.definitions.every((e=>e.kind===y.FRAGMENT_DEFINITION));let p="";if(p=l?s.definitions[0].name.value:(null===(o=s.definitions[0].name)||void 0===o?void 0:o.value)||"",!p)return;p=p.charAt(0).toUpperCase()+p.slice(1);const g=e.parent.getChildren(),u=l?`${p}FragmentDoc`:`${p}Document`,m=` as typeof import('./${t.join(".").replace(".ts","")}').${u}`,d=g.find((e=>a(e)));if(d&&d.getText().includes(u))return;const S={length:1,start:e.end},x=c.text.substring(0,S.start)+m+c.text.substring(S.start+S.length,c.text.length),v=i.project.projectService.getScriptInfo(r),N=v.getSnapshot();c.update(x,{span:S,newLength:m.length}),v.editContent(0,N.getLength(),x),i.languageServiceHost.writeFile(c.fileName,x),v.registerFileUpdate()}))}))}catch(e){}return[...u,...s]},P.getCompletionsAtPosition=(e,a,l)=>{const g=i.languageService.getCompletionsAtPosition(e,a,l)||{isGlobalCompletion:!1,isMemberCompletion:!1,isNewIdentifierLocation:!1,entries:[]},u=b(i,e);if(!u)return g;let m=F(u,a);if(!m)return g;for(;n(m)||s(m)||o(m);)m=m.parent;if(t(m)){const{template:t,tag:n}=m;if(!r(n)||n.text!==p)return g;const o=j(m,e,i),s=I(t,a);if(!s||!A.current)return g;const l=f(A.current,o,new E(s.line,s.start));let u=[];try{u=h(o).definitions.filter((e=>e.kind===y.FRAGMENT_DEFINITION))}catch(e){}return{isGlobalCompletion:!1,isMemberCompletion:!1,isNewIdentifierLocation:!1,entries:[...l.map((e=>({kind:c.variableElement,name:e.label,kindModifiers:"declare",sortText:e.sortText||"0"}))),...u.map((e=>({kind:c.variableElement,name:e.name.value,insertText:"..."+e.name.value,kindModifiers:"declare",sortText:"0"}))),...g.entries]}}return g},P.getQuickInfoAtPosition=(a,c)=>{const l=i.languageService.getQuickInfoAtPosition(a,c),g=b(i,a);if(!g)return l;let f=F(g,c);if(!f)return l;for(;n(f)||s(f)||o(f);)f=f.parent;if(t(f)){const{template:t,tag:n}=f;if(!r(n)||n.text!==p)return l;const o=j(f,a,i),s=I(t,c);if(!s||!A.current)return l;const g=u(A.current,o,new E(s.line,s.start));return{kind:e.ScriptElementKind.string,textSpan:{start:c,length:1},kindModifiers:"",displayParts:Array.isArray(g)?g.map((e=>({kind:"",text:e}))):[{kind:"",text:g}]}}return l},l("proxy: "+JSON.stringify(P)),P}const P=()=>({create:C});export{P as default};