1- import type { Context } from './plugins/context.ts' ;
1+ import type { Context , FileContext , LanguageOptions } from './plugins/context.ts' ;
22import type { CreateOnceRule , Plugin , Rule } from './plugins/load.ts' ;
3+ import type { SourceCode } from './plugins/source_code.ts' ;
34import type { BeforeHook , Visitor , VisitorWithHooks } from './plugins/types.ts' ;
45
56export type * as ESTree from './generated/types.d.ts' ;
@@ -41,7 +42,15 @@ export type {
4142 VisitorWithHooks ,
4243} from './plugins/types.ts' ;
4344
44- const { defineProperty, getPrototypeOf, hasOwn, setPrototypeOf, create : ObjectCreate } = Object ;
45+ const {
46+ defineProperty,
47+ getPrototypeOf,
48+ hasOwn,
49+ setPrototypeOf,
50+ create : ObjectCreate ,
51+ freeze,
52+ assign : ObjectAssign ,
53+ } = Object ;
4554
4655/**
4756 * Define a plugin.
@@ -125,6 +134,81 @@ export function defineRule(rule: Rule): Rule {
125134 return rule ;
126135}
127136
137+ // Cached current working directory
138+ let cwd : string | null = null ;
139+
140+ // File context object. Used as prototype for `Context` objects for each rule during `createOnce` call.
141+ // When running the rules, ESLint's `context` object is switching in as prototype for `Context` objects.
142+ //
143+ // Only `cwd` property and `extends` method are available in `createOnce`, so only those are implemented here.
144+ // All other getters/methods throw, same as they do in main implementation.
145+ const FILE_CONTEXT : FileContext = freeze ( {
146+ get filename ( ) : string {
147+ throw new Error ( 'Cannot access `context.filename` in `createOnce`' ) ;
148+ } ,
149+
150+ get physicalFilename ( ) : string {
151+ throw new Error ( 'Cannot access `context.physicalFilename` in `createOnce`' ) ;
152+ } ,
153+
154+ /**
155+ * Current working directory.
156+ */
157+ get cwd ( ) : string {
158+ // Note: We can allow accessing `cwd` in `createOnce`, as it's global
159+ if ( cwd === null ) cwd = process . cwd ( ) ;
160+ return cwd ;
161+ } ,
162+
163+ get sourceCode ( ) : SourceCode {
164+ throw new Error ( 'Cannot access `context.sourceCode` in `createOnce`' ) ;
165+ } ,
166+
167+ get languageOptions ( ) : LanguageOptions {
168+ throw new Error ( 'Cannot access `context.languageOptions` in `createOnce`' ) ;
169+ } ,
170+
171+ get settings ( ) : Record < string , unknown > {
172+ throw new Error ( 'Cannot access `context.settings` in `createOnce`' ) ;
173+ } ,
174+
175+ /**
176+ * Create a new object with the current object as the prototype and
177+ * the specified properties as its own properties.
178+ * @param extension - The properties to add to the new object.
179+ * @returns A new object with the current object as the prototype
180+ * and the specified properties as its own properties.
181+ */
182+ extend ( this : FileContext , extension : Record < string | number | symbol , unknown > ) : FileContext {
183+ return freeze ( ObjectAssign ( ObjectCreate ( this ) , extension ) ) ;
184+ } ,
185+
186+ get parserOptions ( ) : Record < string , unknown > {
187+ throw new Error ( 'Cannot access `context.parserOptions` in `createOnce`' ) ;
188+ } ,
189+
190+ get parserPath ( ) : string {
191+ throw new Error ( 'Cannot access `context.parserPath` in `createOnce`' ) ;
192+ } ,
193+
194+ getCwd ( ) : string {
195+ // TODO: Implement this?
196+ throw new Error ( '`context.getCwd` is deprecated. Use `cwd` instead.' ) ;
197+ } ,
198+
199+ getFilename ( ) : string {
200+ throw new Error ( 'Cannot call `context.getFilename` in `createOnce`' ) ;
201+ } ,
202+
203+ getPhysicalFilename ( ) : string {
204+ throw new Error ( 'Cannot call `context.getPhysicalFilename` in `createOnce`' ) ;
205+ } ,
206+
207+ getSourceCode ( ) : SourceCode {
208+ throw new Error ( 'Cannot call `context.getSourceCode` in `createOnce`' ) ;
209+ } ,
210+ } ) ;
211+
128212/**
129213 * Call `createOnce` method of rule, and return `Context`, `Visitor`, and `beforeHook` (if any).
130214 *
@@ -142,10 +226,12 @@ function createContextAndVisitor(rule: CreateOnceRule): {
142226 if ( typeof createOnce !== 'function' ) throw new Error ( 'Rule `createOnce` property must be a function' ) ;
143227
144228 // Call `createOnce` with empty context object.
145- // Really, `context` should be an instance of `Context`, which would throw error on accessing e.g. `id`
146- // in body of `createOnce`. But any such bugs should have been caught when testing the rule in Oxlint,
147- // so should be OK to take this shortcut.
148- const context = ObjectCreate ( null , {
229+ // Really, accessing `options` or calling `report` should throw, because they're illegal in `createOnce`.
230+ // But any such bugs should have been caught when testing the rule in Oxlint, so should be OK to take this shortcut.
231+ // `FILE_CONTEXT` prototype provides `cwd` property and `extends` method, which are available in `createOnce`.
232+ const context = ObjectCreate ( FILE_CONTEXT , {
233+ // TODO: Need to set `id` to full rule name - it's available in `createOnce`.
234+ // Or make it inaccessible in `createOnce`.
149235 id : { value : '' , enumerable : true , configurable : true } ,
150236 options : { value : null , enumerable : true , configurable : true } ,
151237 report : { value : null , enumerable : true , configurable : true } ,
0 commit comments