11import { kebabToCamelCase } from '../shared/util' ;
2- import { forEach } from '../util/iterables' ;
2+ import { cloneGrammar } from '../util/extend' ;
3+ import { forEach , toArray } from '../util/iterables' ;
34import { extend } from '../util/language-util' ;
4- import type { ComponentProto , Grammar } from '../types' ;
5+ import type {
6+ ComponentProto ,
7+ Grammar ,
8+ GrammarOptions ,
9+ GrammarOptionsWithBase ,
10+ LanguageProto ,
11+ } from '../types' ;
512import type { Prism } from './prism' ;
613
714interface Entry {
@@ -60,6 +67,13 @@ export class Registry {
6067 // add aliases
6168 forEach ( proto . alias , alias => this . aliasMap . set ( alias , id ) ) ;
6269
70+ if ( ( proto as LanguageProto ) . base ) {
71+ proto . require = [
72+ ( proto as LanguageProto ) . base as ComponentProto ,
73+ ...toArray ( proto . require ) ,
74+ ] ;
75+ }
76+
6377 // dependencies
6478 forEach ( proto . require , register ) ;
6579
@@ -152,11 +166,6 @@ export class Registry {
152166 return entry . evaluatedGrammar ;
153167 }
154168
155- if ( typeof grammar === 'object' ) {
156- // the grammar is a simple object, so we don't need to evaluate it
157- return ( entry . evaluatedGrammar = grammar ) ;
158- }
159-
160169 const required = ( id : string ) : Grammar => {
161170 const grammar = this . getLanguage ( id ) ;
162171 if ( ! grammar ) {
@@ -165,10 +174,33 @@ export class Registry {
165174 return grammar ;
166175 } ;
167176
168- return ( entry . evaluatedGrammar = grammar ( {
169- getLanguage : required ,
170- getOptionalLanguage : id => this . getLanguage ( id ) ,
171- extend : ( id , ref ) => extend ( required ( id ) , id , ref ) ,
172- } ) ) ;
177+ const base = ( entry ?. proto as LanguageProto ) . base ;
178+ // We need this so that any code modifying the base grammar doesn't affect other instances
179+ const baseGrammar = base && cloneGrammar ( required ( base . id ) , base . id ) ;
180+
181+ let evaluatedGrammar : Grammar ;
182+ if ( typeof grammar === 'object' ) {
183+ // if the grammar is an object, we can use it directly
184+ evaluatedGrammar = grammar ;
185+ }
186+ else {
187+ const options : GrammarOptions = {
188+ getLanguage : required ,
189+ getOptionalLanguage : id => this . getLanguage ( id ) ,
190+ extend : ( id , ref ) => extend ( required ( id ) , id , ref ) ,
191+ ...( baseGrammar && { base : baseGrammar } ) ,
192+ } ;
193+
194+ const grammarFn = grammar as (
195+ options : GrammarOptions | GrammarOptionsWithBase
196+ ) => Grammar ;
197+ evaluatedGrammar = grammarFn ( options ) ;
198+ }
199+
200+ if ( baseGrammar ) {
201+ evaluatedGrammar = extend ( baseGrammar , base . id , evaluatedGrammar ) ;
202+ }
203+
204+ return ( entry . evaluatedGrammar = evaluatedGrammar ) ;
173205 }
174206}
0 commit comments