Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint takes too long and has a memory leak #1415

Closed
zepumph opened this issue Jan 4, 2024 · 31 comments
Closed

Lint takes too long and has a memory leak #1415

zepumph opened this issue Jan 4, 2024 · 31 comments

Comments

@zepumph
Copy link
Member

zepumph commented Jan 4, 2024

We originally wrote this as an opt in because we didn't want to bog down type checking and lint with repos that didn't have typescript in them. Now, that is more of the exception than the rule. Perhaps we could use exclude patterns such that we never needed to update this file. This would help prevent errors like phetsims/perennial#347 (comment)

@zepumph zepumph self-assigned this Jan 4, 2024
@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

Here is the how to get the current list of repos with no ts files in their js directories:

/* eslint-env node */

const fs = require( 'fs' );
const path = require( 'path' );
const _ = require( 'lodash' );
const getRepoList = require( '../perennial/js/common/getRepoList' );

const getAllFiles = function( dirPath, arrayOfFiles ) {

  try {
    fs.statSync( dirPath ); // Fails if there is no js/ dir
  }
  catch( e ) {
    return [];
  }

  const files = fs.readdirSync( dirPath );

  arrayOfFiles = arrayOfFiles || [];

  files.forEach( file => {
    if ( fs.statSync( dirPath + '/' + file ).isDirectory() ) {
      arrayOfFiles = getAllFiles( dirPath + '/' + file, arrayOfFiles );
    }
    else {
      arrayOfFiles.push( path.join( __dirname, dirPath, '/', file ) );
    }
  } );

  return arrayOfFiles;
};


const activeRepos = getRepoList( 'active-repos' );
activeRepos.forEach( repo => {
  const allFiles = getAllFiles( `../${repo}/js` );
  if ( !_.some( allFiles, file => file.endsWith( '.ts' ) ) ) {
    console.log( repo );
  }
} );
assert
babel
binder
community
decaf
fenster
monday
phet-info
phet-io-client-guides
phet-io-website
phet-io-wrapper-classroom-activity
phet-io-wrapper-haptics
phet-io-wrapper-hookes-law-energy
phet-io-wrapper-lab-book
phet-lib
phettest
qa
quake
query-string-machine
rosetta
scenery-lab-demo
sherpa
skiffle
tasks
weddell
yotta

@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

I tried something like this, but it seems to take a lot of memory, likely everyone would need to give node 5GB via command line options to get this to work. We should investigate more.

{
  "extends": "../../tsconfig-core.json",
  // Explicitly list all entry points that we want to type check.
  // Imported images/mipmaps/sounds are still type checked.
  // This structure was determined in https://github.com/phetsims/chipper/issues/1245
  "include": [
    "../../../*/js/**/*"
  ],
  "exclude": [
    "../../../release-branches",
    "../../../assert",
    "../../../babel",
    "../../../binder",
    "../../../community",
    "../../../decaf",
    "../../../website",
    "../../../website-meteor",
    "../../../fenster",
    "../../../monday",
    "../../../phet-info",
    "../../../phet-io-client-guides",
    "../../../phet-io-website",
    "../../../phet-io-wrapper-classroom-activity",
    "../../../phet-io-wrapper-haptics",
    "../../../phet-io-wrapper-hookes-law-energy",
    "../../../phet-io-wrapper-lab-book",
    "../../../phet-lib",
    "../../../phettest",
    "../../../qa",
    "../../../quake",
    "../../../query-string-machine",
    "../../../rosetta",
    "../../../scenery-lab-demo",
    "../../../sherpa",
    "../../../skiffle",
    "../../../tasks",
    "../../../weddell",
    "../../../yotta,",
    "../../../patches",
    "../../../quake",
    "../../../skiffle",
    "../../../tmp",
    "../../../sandbox",
    "../../../temp",
    "../../../weddell",
    "../../../yotta",
    "../../../sherpa",



// Just exclude a bunch until we don't have an out of memory error
    "../../../curve-fitting",
    "../../../decaf",
    "../../../density",
    "../../../density-buoyancy-common",
    "../../../diffusion",
    "../../../dot",
    "../../../eating-exercise-and-energy",
    "../../../energy-forms-and-changes",
    "../../../energy-skate-park",
    "../../../energy-skate-park-basics",
    "../../../equality-explorer",
    "../../../equality-explorer-basics",
    "../../../equality-explorer-two-variables",
    "../../../estimation",
    "../../../example-sim",
    "../../../expression-exchange",
    "../../../faradays-electromagnetic-lab",
    "../../../faradays-law",
    "../../../fenster",
    "../../../fluid-pressure-and-flow",
    "../../../forces-and-motion-basics",
    "../../../fourier-making-waves",
    "../../../fraction-comparison",
    "../../../fraction-matcher",
    "../../../fractions-common",
    "../../../fractions-equality",
    "../../../fractions-intro",
    "../../../fractions-mixed-numbers",
    "../../../friction",
    "../../../function-builder",
    "../../../function-builder-basics",
    "../../../gas-properties",
    "../../../gases-intro",
    "../../../gene-expression-essentials",
    "../../../geometric-optics",
    "../../../geometric-optics-basics",
    "../../../graphing-lines",
    "../../../graphing-quadratics",
    "../../../graphing-slope-intercept",
    "../../../gravity-and-orbits",
    "../../../gravity-force-lab",
    "../../../gravity-force-lab-basics",
    "../../../greenhouse-effect",
    "../../../griddle",
    "../../../hookes-law",
    "../../../interaction-dashboard",
    "../../../inverse-square-law-common",
    "../../../isotopes-and-atomic-mass",
    "../../../john-travoltage",
    "../../../joist",
    "../../../keplers-laws",
    "../../../kite",
    "../../../least-squares-regression",
    "../../../make-a-ten",
    "../../../masses-and-springs",
    "../../../masses-and-springs-basics",
    "../../../mean-share-and-balance",
    "../../../mobius",
    "../../../models-of-the-hydrogen-atom",
    "../../../molarity",
    "../../../molecule-polarity",
    "../../../molecule-shapes",
    "../../../molecule-shapes-basics",
    "../../../molecules-and-light",
    "../../../monday",
    "../../../my-solar-system",
    "../../../natural-selection",
    "../../../neuron",
    "../../../nitroglycerin",
    "../../../normal-modes",
    "../../../number-compare",
    "../../../number-line-common",
    "../../../number-line-distance",
    "../../../number-line-integers",
    "../../../number-line-operations",
    "../../../number-play",
    "../../../number-suite-common",
    "../../../ohms-law",
    "../../../optics-lab",
    "../../../patches",
    "../../../pendulum-lab",
    "../../../perennial",
    "../../../perennial-alias",
    "../../../ph-scale",
    "../../../ph-scale-basics",
    "../../../phet-core",
    "../../../phet-info",
    "../../../phet-io",
    "../../../phet-io-client-guides",
    "../../../phet-io-sim-specific",
    "../../../phet-io-test-sim",
    "../../../phet-io-website",
    "../../../phet-io-wrapper-classroom-activity",
    "../../../phet-io-wrapper-haptics",
    "../../../phet-io-wrapper-hookes-law-energy",
    "../../../phet-io-wrapper-lab-book",
    "../../../phet-io-wrappers",
    "../../../phet-lib",
    "../../../phetcommon",
    "../../../phetmarks",
//    "../../../phettest",
//    "../../../plinko-probability",
//    "../../../projectile-data-lab",
//    "../../../projectile-motion",
//    "../../../proportion-playground",
//    "../../../qa",
//    "../../../quadrilateral",
//    "../../../quake",
//    "../../../query-string-machine",
//    "../../../ratio-and-proportion",
//    "../../../reactants-products-and-leftovers",
//    "../../../release-branches",
//    "../../../resistance-in-a-wire",
//    "../../../rosetta",
//    "../../../rutherford-scattering",
//    "../../../sandbox",
//    "../../../scenery",
//    "../../../scenery-lab-demo",
//    "../../../scenery-phet",
//    "../../../sherpa",
//    "../../../shred",
//    "../../../simula-rasa",
//    "../../../skiffle",
//    "../../../soccer-common",
//    "../../../solar-system-common",
//    "../../../sound-waves",
//    "../../../states-of-matter",
//    "../../../states-of-matter-basics",
//    "../../../studio",
//    "../../../sun",
//    "../../../tambo",
//    "../../../tandem",
//    "../../../tangible",
//    "../../../tappi",
//    "../../../tasks",
//    "../../../tmp",
//    "../../../trig-tour",
//
//    "../../../twixt",
//    "../../../under-pressure",
//    "../../../unit-rates",
//    "../../../utterance-queue",
//    "../../../vector-addition",
//    "../../../vector-addition-equations",
//    "../../../vegas",
//    "../../../vibe",
//    "../../../wave-interference",
//    "../../../wave-on-a-string",
//    "../../../waves-intro",
//    "../../../weddell",
//    "../../../wilder",
//    "../../../xray-diffraction",
//    "../../../yotta",
  ]
}

@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

When I try to include all sims that should be getting checking, this error occurs when Node is taking up ~4.9GB of memory in the tsc process:

 mjkauzmann ~/PHET/git/chipper/tsconfig/all (main)
 $ time tsc
C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:114743
      throw e;
      ^

Error: Debug Failure.
    at visitEachChildOfIndexSignatureDeclaration (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83740:13)
    at visitEachChild (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83596:33)
    at visitExistingNodeTreeSymbols (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:49006:16)
    at visitArrayWorker (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83408:49)
    at visitNodes2 (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83379:19)
    at visitEachChildOfTypeLiteralNode (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83786:7)
    at visitEachChild (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83596:33)
    at visitExistingNodeTreeSymbols (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:49006:16)
    at visitArrayWorker (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83408:49)
    at visitNodes2 (C:\Users\mjkauzmann\PHET\git\chipper\node_modules\typescript\lib\tsc.js:83379:19)

Node.js v18.16.0

real    3m7.755s
user    0m0.000s
sys     0m0.000s

@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

I'd like to discuss with @samreid before proceeding.

@samreid
Copy link
Member

samreid commented Jan 5, 2024

@zepumph and I found that we can only get to around 100 simulation entry points before crashing. It seems the solution is to use project references, probably like described in #1356.

Compared to where we are now, this means we could add another 30-60 entry points at most before we cannot run it any more.

@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

I believe this was helpful in investigating the EOL on the monolithic approach. Likely one day we will hit this, and linting will no longer work. Let's up the priority of #1356 so that we use project references BEFORE that happens. I bet we have 6 months of confident grace, and ~1 year before we start getting quite risky. Thanks for your time @samreid.

@zepumph
Copy link
Member Author

zepumph commented Jan 5, 2024

eslint's project uses the exact same code path as running tsc, at least as far as getting the heap memory error. If I use a generalized "include everything" config for eslint, it still runs out of memory:

{
  "extends": "../../tsconfig-core.json",
  "include": [
    "../../../**/*"
  ],
  "exclude": [
    "**/node_modules",
    "**/.git"
  ]
}

@samreid samreid reopened this Mar 14, 2024
@samreid samreid removed their assignment Mar 14, 2024
@samreid samreid assigned samreid and unassigned zepumph Mar 14, 2024
@samreid
Copy link
Member

samreid commented Mar 14, 2024

Some experimental results:

  1. I added all active-sims to tsconfig/all
  2. I confirmed that grunt lint-everything caused a memory crash
  3. I tried pointing .eslintrc to
  overrides: [
    {
      files: [ '*.html' ],
      rules: {
        // DUPLICATION ALERT, this overrides the base rule, just for HTML.
        'no-multiple-empty-lines': [ 'error', { max: 2, maxBOF: 2, maxEOF: 1 } ],
        'bad-sim-text': 'off'
      }
    },
    {

      // For .ts files, the following configuration will be used
      files: [
        '**/*.ts',
        '**/*.tsx'
      ],
      parser: '@typescript-eslint/parser',
      parserOptions: {
        sourceType: 'module',

        // Provide a tsconfig so that we can use rules that require type information.
        // NOTE: Providing this slows down eslint substantially, see https://github.com/phetsims/chipper/issues/1114#issuecomment-1065927717
        project: [ `../${global.myFancyRepo}/tsconfig.json` ]
      },

And it was still a heap crash.

  1. However, I tried running lintOneRepo in a separate process via fork and that ran smoothly and kept under the memory limit for grunt lint-everything.
  2. However, tsc in tsconfig/all failed with an out of memory error:
~/phet/root/chipper/tsconfig/all$ tsc

<--- Last few GCs --->

[51248:0x128008000]    75368 ms: Mark-Compact 4040.1 (4140.6) -> 4027.0 (4143.4) MB, 661.92 / 0.00 ms  (average mu = 0.525, current mu = 0.063) allocation failure; scavenge might not succeed
[51248:0x128008000]    76772 ms: Mark-Compact 4043.3 (4143.6) -> 4028.8 (4145.1) MB, 1366.46 / 0.04 ms  (average mu = 0.271, current mu = 0.027) allocation failure; scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0x100340bf4 node::Abort() [/usr/local/bin/node]
 2: 0x100340ddc node::ModifyCodeGenerationFromStrings(v8::Local<v8::Context>, v8::Local<v8::Value>, bool) [/usr/local/bin/node]
 3: 0x1004c4da8 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/usr/local/bin/node]
etc...

Changing the package.json to point to the tsconfig could make this work. However, in doing so, the IDE catches errors but grunt lint does not.

Experimental patch:

Subject: [PATCH] Remove unused css, see https://github.com/phetsims/projectile-data-lab/issues/233
---
Index: chipper/js/grunt/lint.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/js/grunt/lint.js b/chipper/js/grunt/lint.js
--- a/chipper/js/grunt/lint.js	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/js/grunt/lint.js	(date 1710384485963)
@@ -33,95 +33,63 @@
   console.log( `\n${resultText}\n` );
 }
 
+const { fork } = require( 'child_process' );
+const path = require( 'path' );
+
+const lintOneRepo = async ( repo, options ) => {
+  console.log( 'Linting the repo: ' + repo );
+
+  // Use path.join for constructing the path for better OS compatibility
+  const workerScriptPath = path.join( __dirname, 'lintRepoWorker.js' );
+
+  return new Promise( ( resolve, reject ) => {
+    const child = fork( workerScriptPath, {
+      stdio: 'inherit'
+    } );
+
+    let results = null; // Placeholder for results from the child process
+
+    child.on( 'message', ( message ) => {
+      // Store results from child process to resolve later
+      results = message.results;
+    } );
+
+    child.on( 'error', ( error ) => {
+      // Reject the promise if an error occurs in the child process
+      reject( error );
+    } );
+
+    child.on( 'exit', ( code ) => {
+      if ( code === 0 ) {
+        // Resolve the promise with the results upon successful completion
+        if ( results !== null ) {
+          resolve( results );
+        }
+        else {
+          // Resolve with no results if message wasn't received but exit code is 0
+          resolve( [] );
+        }
+      }
+      else {
+        // Reject the promise if the child process exits with an error code
+        reject( new Error( `Child process exited with code ${code}` ) );
+      }
+    } );
+
+    // Send repo and options to child process
+    child.send( { repo, options } );
+  } );
+};
+
 /**
  * Create an ESLint client and lint a single repo
  * @param {string} repo
  * @param {Object} [options]
  * @returns {Promise<Object>} - results from linting files, see ESLint.lintFiles
  */
-const lintOneRepo = async ( repo, options ) => {
-
-  options = _.assignIn( {
-    cache: true,
-    fix: false,
-    format: false,
-    inProgressErrorLogging: false // print out the
-  }, options );
-
-  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known memory leak.  May
-  // need to clear the cache directory in a few years?
-  const tsconfigFile = fs.readFileSync( '../chipper/tsconfig/all/tsconfig.json', 'utf-8' );
-
-  // Also cache on package.json so that when eslint plugins change, it will invalidate the caches. Note this will
-  // have false positives because it is possible to change package.json without changing
-  // the eslint plugins
-  const packageJSON = fs.readFileSync( '../chipper/package.json', 'utf-8' );
-
-  const hash = crypto.createHash( 'md5' ).update( tsconfigFile + packageJSON ).digest( 'hex' );
+// const lintOneRepo = async ( repo, options ) => {
 
-  const eslintConfig = {
-
-    // optional auto-fix
-    fix: options.fix,
-
-    // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
-    // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
-    // the process was run from. If false, this will delete the `cacheLocation` file.
-    cache: options.cache,
-
-    // Where to store the target-specific cache file.  Use only first 4 digits of hash to improve readability
-    // at the risk of having more key collisions
-    cacheLocation: `../chipper/eslint/cache/${repo}-${hash.substring( 0, 8 )}.eslintcache`,
-
-    ignorePath: '../chipper/eslint/.eslintignore',
-
-    resolvePluginsRelativeTo: '../chipper/',
-
-    // Our custom rules live here
-    rulePaths: [ '../chipper/eslint/rules' ],
-
-    extensions: [ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.html' ],
-
-    // If no lintable files are found, it is not an error
-    errorOnUnmatchedPattern: false
-  };
-
-  const cacheKey = `lintRepo#${repo}`;
-
-  if ( options.cache && CacheLayer.isCacheSafe( cacheKey ) ) {
-    // console.log( 'lint cache hit: ' + cacheKey );
-    return [];
-  }
-  else {
-    // console.log( 'lint cache fail: ' + cacheKey );
-  }
-
-  const config = {};
-  const configExtends = [];
-  if ( options.format ) {
-    configExtends.push( '../chipper/eslint/format_eslintrc.js' );
-  }
-
-  config.extends = configExtends;
-  eslintConfig.baseConfig = config;
-
-  const eslint = new ESLint( eslintConfig );
-
-  const results = await eslint.lintFiles( repoToPattern( repo ) );
-
-  const totalWarnings = _.sum( results.map( result => result.warningCount ) );
-  const totalErrors = _.sum( results.map( result => result.errorCount ) );
-  if ( options.cache && totalWarnings === 0 && totalErrors === 0 ) {
-    CacheLayer.onSuccess( cacheKey );
-  }
-
-  if ( options.inProgressErrorLogging && totalWarnings + totalErrors > 0 ) {
-    console.log( `\n\n${repo}:` );
-    await consoleLogResults( results );
-  }
-
-  return results;
-};
+// };
 
 /**
  * Lints the specified repositories.
Index: chipper/tsconfig/all/tsconfig.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/tsconfig/all/tsconfig.json b/chipper/tsconfig/all/tsconfig.json
--- a/chipper/tsconfig/all/tsconfig.json	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/tsconfig/all/tsconfig.json	(date 1710381593802)
@@ -125,6 +125,139 @@
     "../../../vector-addition/js/**/*",
     "../../../vegas/js/**/*",
     "../../../wave-interference/js/**/*",
-    "../../../wilder/js/**/*"
+    "../../../wilder/js/**/*",
+
+    "../../../acid-base-solutions/js/**/*",
+    "../../../area-builder/js/**/*",
+    "../../../area-model-algebra/js/**/*",
+    "../../../area-model-decimals/js/**/*",
+    "../../../area-model-introduction/js/**/*",
+    "../../../area-model-multiplication/js/**/*",
+    "../../../arithmetic/js/**/*",
+    "../../../atomic-interactions/js/**/*",
+    "../../../balancing-act/js/**/*",
+    "../../../balancing-chemical-equations/js/**/*",
+    "../../../balloons-and-static-electricity/js/**/*",
+    "../../../beers-law-lab/js/**/*",
+    "../../../bending-light/js/**/*",
+    "../../../blackbody-spectrum/js/**/*",
+    "../../../blast/js/**/*",
+    "../../../build-a-fraction/js/**/*",
+    "../../../build-a-molecule/js/**/*",
+    "../../../build-a-nucleus/js/**/*",
+    "../../../build-an-atom/js/**/*",
+    "../../../bumper/js/**/*",
+    "../../../buoyancy/js/**/*",
+    "../../../buoyancy-basics/js/**/*",
+    "../../../calculus-grapher/js/**/*",
+    "../../../capacitor-lab-basics/js/**/*",
+    "../../../center-and-variability/js/**/*",
+    "../../../chains/js/**/*",
+    "../../../charges-and-fields/js/**/*",
+    "../../../circuit-construction-kit-ac/js/**/*",
+    "../../../circuit-construction-kit-ac-virtual-lab/js/**/*",
+    "../../../circuit-construction-kit-black-box-study/js/**/*",
+    "../../../circuit-construction-kit-dc/js/**/*",
+    "../../../circuit-construction-kit-dc-virtual-lab/js/**/*",
+    "../../../collision-lab/js/**/*",
+    "../../../color-vision/js/**/*",
+    "../../../concentration/js/**/*",
+    "../../../coulombs-law/js/**/*",
+    "../../../curve-fitting/js/**/*",
+    "../../../density/js/**/*",
+    "../../../diffusion/js/**/*",
+    "../../../eating-exercise-and-energy/js/**/*",
+    "../../../energy-forms-and-changes/js/**/*",
+    "../../../energy-skate-park/js/**/*",
+    "../../../energy-skate-park-basics/js/**/*",
+    "../../../equality-explorer/js/**/*",
+    "../../../equality-explorer-basics/js/**/*",
+    "../../../equality-explorer-two-variables/js/**/*",
+    "../../../estimation/js/**/*",
+    "../../../example-sim/js/**/*",
+    "../../../expression-exchange/js/**/*",
+    "../../../faradays-electromagnetic-lab/js/**/*",
+    "../../../faradays-law/js/**/*",
+    "../../../fluid-pressure-and-flow/js/**/*",
+    "../../../forces-and-motion-basics/js/**/*",
+    "../../../fourier-making-waves/js/**/*",
+    "../../../fraction-comparison/js/**/*",
+    "../../../fraction-matcher/js/**/*",
+    "../../../fractions-equality/js/**/*",
+    "../../../fractions-intro/js/**/*",
+    "../../../fractions-mixed-numbers/js/**/*",
+    "../../../friction/js/**/*",
+    "../../../function-builder/js/**/*",
+    "../../../function-builder-basics/js/**/*",
+    "../../../gas-properties/js/**/*",
+    "../../../gases-intro/js/**/*",
+    "../../../gene-expression-essentials/js/**/*",
+    "../../../generator/js/**/*",
+    "../../../geometric-optics/js/**/*",
+    "../../../geometric-optics-basics/js/**/*",
+    "../../../graphing-lines/js/**/*",
+    "../../../graphing-quadratics/js/**/*",
+    "../../../graphing-slope-intercept/js/**/*",
+    "../../../gravity-and-orbits/js/**/*",
+    "../../../gravity-force-lab/js/**/*",
+    "../../../gravity-force-lab-basics/js/**/*",
+    "../../../greenhouse-effect/js/**/*",
+    "../../../hookes-law/js/**/*",
+    "../../../interaction-dashboard/js/**/*",
+    "../../../isotopes-and-atomic-mass/js/**/*",
+    "../../../john-travoltage/js/**/*",
+    "../../../keplers-laws/js/**/*",
+    "../../../least-squares-regression/js/**/*",
+    "../../../magnet-and-compass/js/**/*",
+    "../../../magnets-and-electromagnets/js/**/*",
+    "../../../make-a-ten/js/**/*",
+    "../../../masses-and-springs/js/**/*",
+    "../../../masses-and-springs-basics/js/**/*",
+    "../../../mean-share-and-balance/js/**/*",
+    "../../../models-of-the-hydrogen-atom/js/**/*",
+    "../../../molarity/js/**/*",
+    "../../../molecule-polarity/js/**/*",
+    "../../../molecule-shapes/js/**/*",
+    "../../../molecule-shapes-basics/js/**/*",
+    "../../../molecules-and-light/js/**/*",
+    "../../../my-solar-system/js/**/*",
+    "../../../natural-selection/js/**/*",
+    "../../../neuron/js/**/*",
+    "../../../normal-modes/js/**/*",
+    "../../../number-compare/js/**/*",
+    "../../../number-line-distance/js/**/*",
+    "../../../number-line-integers/js/**/*",
+    "../../../number-line-operations/js/**/*",
+    "../../../number-play/js/**/*",
+    "../../../ohms-law/js/**/*",
+    "../../../optics-lab/js/**/*",
+    "../../../pendulum-lab/js/**/*",
+    "../../../ph-scale/js/**/*",
+    "../../../ph-scale-basics/js/**/*",
+    "../../../phet-io-test-sim/js/**/*",
+    "../../../plinko-probability/js/**/*",
+    "../../../projectile-motion/js/**/*",
+    "../../../projectile-data-lab/js/**/*",
+    "../../../proportion-playground/js/**/*",
+    "../../../quadrilateral/js/**/*",
+    "../../../ratio-and-proportion/js/**/*",
+    "../../../reactants-products-and-leftovers/js/**/*",
+    "../../../resistance-in-a-wire/js/**/*",
+    "../../../rutherford-scattering/js/**/*",
+    "../../../simula-rasa/js/**/*",
+    "../../../sound-waves/js/**/*",
+    "../../../states-of-matter/js/**/*",
+    "../../../states-of-matter-basics/js/**/*",
+    "../../../trig-tour/js/**/*",
+    "../../../under-pressure/js/**/*",
+    "../../../unit-rates/js/**/*",
+    "../../../vector-addition/js/**/*",
+    "../../../vector-addition-equations/js/**/*",
+    "../../../wave-interference/js/**/*",
+    "../../../wave-on-a-string/js/**/*",
+    "../../../waves-intro/js/**/*",
+    "../../../wilder/js/**/*",
+    "../../../xray-diffraction/js/**/*",
+
   ]
 }
\ No newline at end of file
Index: chipper/eslint/.eslintrc.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/eslint/.eslintrc.js b/chipper/eslint/.eslintrc.js
--- a/chipper/eslint/.eslintrc.js	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/eslint/.eslintrc.js	(date 1710384247374)
@@ -41,7 +41,7 @@
 
         // Provide a tsconfig so that we can use rules that require type information.
         // NOTE: Providing this slows down eslint substantially, see https://github.com/phetsims/chipper/issues/1114#issuecomment-1065927717
-        project: [ '../chipper/tsconfig/all/tsconfig.json' ]
+        project: [ `../${global.myFancyRepo}/tsconfig.json` ]
       },
       plugins: [
         '@typescript-eslint'
Index: projectile-data-lab/js/common/model/Field.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/projectile-data-lab/js/common/model/Field.ts b/projectile-data-lab/js/common/model/Field.ts
--- a/projectile-data-lab/js/common/model/Field.ts	(revision 5d387795957446a92d9d439511035cfd0f6d6a51)
+++ b/projectile-data-lab/js/common/model/Field.ts	(date 1710384458893)
@@ -39,7 +39,7 @@
 import PDLPreferences from '../PDLPreferences.js';
 import StringUnionProperty from '../../../../axon/js/StringUnionProperty.js';
 
-const launchSoundClip = new SoundClip( launch_mp3, { initialOutputLevel: 0.2 } );
+const launchSoundClip = new SoundClip(    launch_mp3, { initialOutputLevel: 0.2 } );
 soundManager.addSoundGenerator( launchSoundClip );
 
 type SelfOptions = {
@@ -63,6 +63,12 @@
   // Specifies the type of projectile being used.
   public readonly projectileTypeProperty: Property<ProjectileType>;
 
+
+
+
+
+
+
   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // These values are DynamicProperties that are determined by the Launcher, see Launcher.ts and implementation-notes.md
 
Index: projectile-data-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/projectile-data-lab/package.json b/projectile-data-lab/package.json
--- a/projectile-data-lab/package.json	(revision 5d387795957446a92d9d439511035cfd0f6d6a51)
+++ b/projectile-data-lab/package.json	(date 1710384368908)
@@ -46,6 +46,9 @@
         "files": [
           "**/*.ts"
         ],
+        "parserOptions": {
+          "project": [ "../projectile-data-lab/tsconfig.json" ]
+        },
         "rules": {
           "@typescript-eslint/ban-ts-comment": [
             "error",
Index: chipper/js/grunt/lintRepoWorker.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/js/grunt/lintRepoWorker.js b/chipper/js/grunt/lintRepoWorker.js
new file mode 100644
--- /dev/null	(date 1710384547964)
+++ b/chipper/js/grunt/lintRepoWorker.js	(date 1710384547964)
@@ -0,0 +1,135 @@
+// lintRepoWorker.js
+const fs = require( 'fs' );
+const CacheLayer = require( '../common/CacheLayer' );
+const crypto = require( 'crypto' );
+const { ESLint } = require( 'eslint' );
+const _ = require( 'lodash' );
+// Import other necessary modules and initialize them here
+
+// constants
+const EXCLUDE_REPOS = [ 'binder', 'fenster', 'decaf', 'scenery-lab-demo' ];
+
+// "Pattern" is really a path, we assume here that gruntfiles help keep the right directory structure and can just pop
+// out of the repo running the command
+const repoToPattern = repo => `../${repo}`;
+
+process.on( 'message', async ( message ) => {
+  const { repo, options } = message;
+  // Place your linting logic here, similar to what you have in lintOneRepo
+
+  // For example:
+  const results = await lintRepoLogic( repo, options ); // Implement lintRepoLogic based on your existing linting logic
+
+  // Send results back to the parent process
+  process.send( { results } );
+  process.exit( 0 );
+} );
+
+async function consoleLogResults( results ) {
+
+  // No need to have the same ESLint just to format
+  const formatter = await new ESLint().loadFormatter( 'stylish' );
+  const resultText = formatter.format( results );
+  console.log( `\n${resultText}\n` );
+}
+
+process.on( 'uncaughtException', ( error ) => {
+  console.error( 'Uncaught Exception:', error );
+  process.exit( 1 ); // Ensure the process exits with an error code
+} );
+
+process.on( 'unhandledRejection', ( reason, promise ) => {
+  console.error( 'Unhandled Rejection at:', promise, 'reason:', reason );
+  process.exit( 1 ); // Ensure the process exits with an error code
+} );
+
+
+// You might need to adapt the function to be more suited for this usage.
+async function lintRepoLogic( repo, options ) {
+
+  // @ts-expect-error
+  console.log( 'worker linting the repo: ' + repo );
+
+  global.myFancyRepo = repo;
+
+  options = _.assignIn( {
+    cache: true,
+    fix: false,
+    format: false,
+    inProgressErrorLogging: false // print out the
+  }, options );
+
+  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known memory leak.  May
+  // need to clear the cache directory in a few years?
+  const tsconfigFile = fs.readFileSync( '../chipper/tsconfig/all/tsconfig.json', 'utf-8' );
+
+  // Also cache on package.json so that when eslint plugins change, it will invalidate the caches. Note this will
+  // have false positives because it is possible to change package.json without changing
+  // the eslint plugins
+  const packageJSON = fs.readFileSync( '../chipper/package.json', 'utf-8' );
+
+  const hash = crypto.createHash( 'md5' ).update( tsconfigFile + packageJSON ).digest( 'hex' );
+
+  const eslintConfig = {
+
+    // optional auto-fix
+    fix: options.fix,
+
+    // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
+    // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
+    // the process was run from. If false, this will delete the `cacheLocation` file.
+    cache: options.cache,
+
+    // Where to store the target-specific cache file.  Use only first 4 digits of hash to improve readability
+    // at the risk of having more key collisions
+    cacheLocation: `../chipper/eslint/cache/${repo}-${hash.substring( 0, 8 )}.eslintcache`,
+
+    ignorePath: '../chipper/eslint/.eslintignore',
+
+    resolvePluginsRelativeTo: '../chipper/',
+
+    // Our custom rules live here
+    rulePaths: [ '../chipper/eslint/rules' ],
+
+    extensions: [ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.html' ],
+
+    // If no lintable files are found, it is not an error
+    errorOnUnmatchedPattern: false
+  };
+
+  const cacheKey = `lintRepo#${repo}`;
+
+  if ( options.cache && CacheLayer.isCacheSafe( cacheKey ) ) {
+    // console.log( 'lint cache hit: ' + cacheKey );
+    return [];
+  }
+  else {
+    // console.log( 'lint cache fail: ' + cacheKey );
+  }
+
+  const config = {};
+  const configExtends = [];
+  if ( options.format ) {
+    configExtends.push( '../chipper/eslint/format_eslintrc.js' );
+  }
+
+  config.extends = configExtends;
+  eslintConfig.baseConfig = config;
+
+  const eslint = new ESLint( eslintConfig );
+
+  const results = await eslint.lintFiles( repoToPattern( repo ) );
+
+  const totalWarnings = _.sum( results.map( result => result.warningCount ) );
+  const totalErrors = _.sum( results.map( result => result.errorCount ) );
+  if ( options.cache && totalWarnings === 0 && totalErrors === 0 ) {
+    CacheLayer.onSuccess( cacheKey );
+  }
+
+  if ( options.inProgressErrorLogging && totalWarnings + totalErrors > 0 ) {
+    console.log( `\n\n${repo}:` );
+    await consoleLogResults( results );
+  }
+
+  return results;
+}
\ No newline at end of file

It was OK after a memory boost though:

~/phet/root/chipper/tsconfig/all$ node --max-old-space-size=8192 /Users/samreid/phet/root/chipper/node_modules/typescript/bin/tsc
~/phet/root/chipper/tsconfig/all$ 

@samreid
Copy link
Member

samreid commented Mar 15, 2024

In discussion, @matthew-blackman @zepumph @jonathanolson and I discussed that we want to move forward with the package.json lint entry points, and I will take the lead on that. That will help with linting. In #1356 we talked about a long term goal of having d.ts files, so that will help with the type checking everything maybe.

@zepumph
Copy link
Member Author

zepumph commented Mar 15, 2024

@samreid
Copy link
Member

samreid commented Mar 16, 2024

I tracked down memory leaks to typescript-eslint and the eslint project itself. First, we are suffering from the same problem as: typescript-eslint/typescript-eslint#6462. Please note also the flag process.env.TSESTREE_SINGLE_RUN = 'true' which will probably be helpful for our case.

I tried the workaround listed there and it seemed to help. Instead of memory failing at 15% repos, it makes it to 35% repos.

Here is that patch so far:

Subject: [PATCH] Rename angleStabilizerProperty => angleStabilityProperty and related names, see https://github.com/phetsims/projectile-data-lab/issues/252
---
Index: js/grunt/lint.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/grunt/lint.js b/js/grunt/lint.js
--- a/js/grunt/lint.js	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/js/grunt/lint.js	(date 1710604455704)
@@ -18,6 +18,10 @@
 const CacheLayer = require( '../common/CacheLayer' );
 const crypto = require( 'crypto' );
 
+const exported = require( '../../../chipper/node_modules/@typescript-eslint/typescript-estree/dist/index.js' );
+const clearCaches = clearCachesExport.clearCaches;
+debugger;
+
 // constants
 const EXCLUDE_REPOS = [ 'binder', 'fenster', 'decaf', 'scenery-lab-demo' ];
 
@@ -25,6 +29,8 @@
 // out of the repo running the command
 const repoToPattern = repo => `../${repo}`;
 
+process.env.TSESTREE_SINGLE_RUN = 'true'
+
 async function consoleLogResults( results ) {
 
   // No need to have the same ESLint just to format
@@ -48,9 +54,15 @@
     inProgressErrorLogging: false // print out the
   }, options );
 
-  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known memory leak.  May
-  // need to clear the cache directory in a few years?
-  const tsconfigFile = fs.readFileSync( '../chipper/tsconfig/all/tsconfig.json', 'utf-8' );
+  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known file system leak, because
+  // the old cache directory is not cleared when a new one is formed.  May need to clear the cache directory manually in a few years?
+  let tsconfigFile = '';
+  try {
+    tsconfigFile = fs.readFileSync( `../${repo}/tsconfig.json`, 'utf-8' );
+  }
+  catch( e ) {
+    // tsconfig file not found
+  }
 
   // Also cache on package.json so that when eslint plugins change, it will invalidate the caches. Note this will
   // have false positives because it is possible to change package.json without changing
@@ -120,6 +132,8 @@
     await consoleLogResults( results );
   }
 
+  clearCaches();
+
   return results;
 };
 
Index: package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/package.json b/package.json
--- a/package.json	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/package.json	(date 1710555475915)
@@ -27,16 +27,16 @@
     "@types/three": "~0.137.0",
     "@types/react": "~18.0.12",
     "@types/react-dom": "~18.0.5",
-    "@typescript-eslint/parser": "~6.18.1",
-    "@typescript-eslint/eslint-plugin": "~6.18.1",
-    "@typescript-eslint/utils": "~6.18.1",
-    "eslint-plugin-html": "~7.1.0",
+    "@typescript-eslint/parser": "~7.2.0",
+    "@typescript-eslint/eslint-plugin": "~7.2.0",
+    "@typescript-eslint/utils": "~7.2.0",
+    "eslint-plugin-html": "~8.0.0",
     "@webgpu/types": "~0.1.34",
     "archiver": "~5.3.0",
     "axios": "~0.21.4",
     "@babel/eslint-parser": "~7.19.1",
     "docdash": "~1.2.0",
-    "eslint": "~8.28.0",
+    "eslint": "~8.57.0",
     "eslint-plugin-react": "~7.31.11",
     "expose-loader": "~4.1.0",
     "grunt": "~1.5.3",
@@ -82,8 +82,13 @@
           "**/*.ts",
           "**/*.tsx"
         ],
-        "parser": "@typescript-eslint/parser"
+        "parser": "@typescript-eslint/parser",
+        "parserOptions": {
+          "project": [
+            "../chipper/tsconfig.json"
+          ]
+        }
       }
     ]
   }
-}
+}
\ No newline at end of file

Note this is clear-caches.js from typescript-eslint:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearProgramCache = exports.clearCaches = void 0;
const getWatchProgramsForProjects_1 = require("./create-program/getWatchProgramsForProjects");
const parser_1 = require("./parser");
const createParseSettings_1 = require("./parseSettings/createParseSettings");
const resolveProjectList_1 = require("./parseSettings/resolveProjectList");
/**
 * Clears all of the internal caches.
 * Generally you shouldn't need or want to use this.
 * Examples of intended uses:
 * - In tests to reset parser state to keep tests isolated.
 * - In custom lint tooling that iteratively lints one project at a time to prevent OOMs.
 */
function clearCaches() {
    (0, parser_1.clearProgramCache)();
    (0, getWatchProgramsForProjects_1.clearWatchCaches)();
    (0, createParseSettings_1.clearTSConfigMatchCache)();
    (0, createParseSettings_1.clearTSServerProjectService)();
    (0, resolveProjectList_1.clearGlobCache)();
}
exports.clearCaches = clearCaches;
// TODO - delete this in next major
exports.clearProgramCache = clearCaches;
//# sourceMappingURL=clear-caches.js.map

There are more memory leaks after that appear to be related to eslint itself. Here is a screenshot of that memory usage:

image

I do not see an API for clearing these in-memory caches. Therefore it seems reasonable to experiment with running the lintOneFile in a separate fork or process, since we can guarantee that won't leak any internal memory caches.

Please be advised that fork/process overhead on Windows is very different than on mac, so please performance test on Windows before getting too far.

@samreid
Copy link
Member

samreid commented Mar 19, 2024

Patch that introduces lintMain and batches in lint-everything. I'll probably need help getting this to production.

Subject: [PATCH] Rename angleStabilizerProperty => angleStabilityProperty and related names, see https://github.com/phetsims/projectile-data-lab/issues/252
---
Index: generator/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/generator/package.json b/generator/package.json
--- a/generator/package.json	(revision 41b8aad8b81f37833b335710c58e8f585de0c6f9)
+++ b/generator/package.json	(date 1710537716961)
@@ -49,6 +49,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../generator/tsconfig.json"
+          ]
         }
       }
     ]
Index: chipper/eslint/.eslintrc.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/eslint/.eslintrc.js b/chipper/eslint/.eslintrc.js
--- a/chipper/eslint/.eslintrc.js	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/eslint/.eslintrc.js	(date 1710545322443)
@@ -37,11 +37,12 @@
       ],
       parser: '@typescript-eslint/parser',
       parserOptions: {
-        sourceType: 'module',
+        sourceType: 'module'
 
         // Provide a tsconfig so that we can use rules that require type information.
         // NOTE: Providing this slows down eslint substantially, see https://github.com/phetsims/chipper/issues/1114#issuecomment-1065927717
-        project: [ '../chipper/tsconfig/all/tsconfig.json' ]
+        // The project must be specified in the repo-specific package.json eslintConfig.overrides.
+        // project: [ '../{{repo}}/tsconfig.json' ]
       },
       plugins: [
         '@typescript-eslint'
Index: density-buoyancy-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/density-buoyancy-common/package.json b/density-buoyancy-common/package.json
--- a/density-buoyancy-common/package.json	(revision b445068b64ba0236ae354426c9c44a3cd6c41398)
+++ b/density-buoyancy-common/package.json	(date 1710537715994)
@@ -24,6 +24,18 @@
       "p2": "readonly",
       "THREE": "readonly",
       "decomp": "readonly"
-    }
-  }
-}
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../density-buoyancy-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: density/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/density/package.json b/density/package.json
--- a/density/package.json	(revision a3023fed555b3b94bcea8b1f879d424f07a674e6)
+++ b/density/package.json	(date 1710537715963)
@@ -50,6 +50,18 @@
       "p2": "readonly",
       "THREE": "readonly",
       "decomp": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../density/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: diffusion/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/diffusion/package.json b/diffusion/package.json
--- a/diffusion/package.json	(revision eb2bc64aa7f4cb35477aafc48f2b23174bb50d1c)
+++ b/diffusion/package.json	(date 1710537716027)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../diffusion/tsconfig.json"
+          ]
         }
       }
     ]
Index: dot/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/dot/package.json b/dot/package.json
--- a/dot/package.json	(revision d8a7a56f496da90dc0115c18a1d08cff89360791)
+++ b/dot/package.json	(date 1710537716058)
@@ -23,6 +23,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../dot/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: eating-exercise-and-energy/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/eating-exercise-and-energy/package.json b/eating-exercise-and-energy/package.json
--- a/eating-exercise-and-energy/package.json	(revision d30ad45d566b1549d3d11c9987785f400610d40a)
+++ b/eating-exercise-and-energy/package.json	(date 1710537716088)
@@ -20,6 +20,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../eating-exercise-and-energy/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: energy-forms-and-changes/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/energy-forms-and-changes/package.json b/energy-forms-and-changes/package.json
--- a/energy-forms-and-changes/package.json	(revision 222a88509b71a9c2ad75e81cbb4cd372038375fc)
+++ b/energy-forms-and-changes/package.json	(date 1710537716119)
@@ -32,6 +32,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../energy-forms-and-changes/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: energy-skate-park-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/energy-skate-park-basics/package.json b/energy-skate-park-basics/package.json
--- a/energy-skate-park-basics/package.json	(revision 3a02721ac1a6d113b18ab65497917bb574a7bd80)
+++ b/energy-skate-park-basics/package.json	(date 1710537716180)
@@ -48,6 +48,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../energy-skate-park-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: energy-skate-park/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/energy-skate-park/package.json b/energy-skate-park/package.json
--- a/energy-skate-park/package.json	(revision 21a480200a3457ae8204d77f9ffa44d3d1462f58)
+++ b/energy-skate-park/package.json	(date 1710537716150)
@@ -51,6 +51,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "globals": {
       "numeric": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../energy-skate-park/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: equality-explorer-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/equality-explorer-basics/package.json b/equality-explorer-basics/package.json
--- a/equality-explorer-basics/package.json	(revision fb0252d032b7789fc8e6a5214f741d2a4fe12b3b)
+++ b/equality-explorer-basics/package.json	(date 1710537716242)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../equality-explorer-basics/tsconfig.json"
+          ]
         }
       }
     ]
Index: equality-explorer-two-variables/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/equality-explorer-two-variables/package.json b/equality-explorer-two-variables/package.json
--- a/equality-explorer-two-variables/package.json	(revision 54cfb215f6795ff832e553d72fee1a8a24ae3171)
+++ b/equality-explorer-two-variables/package.json	(date 1710537716273)
@@ -52,6 +52,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../equality-explorer-two-variables/tsconfig.json"
+          ]
         }
       }
     ]
Index: equality-explorer/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/equality-explorer/package.json b/equality-explorer/package.json
--- a/equality-explorer/package.json	(revision 6e24460cc9b1bcc3ff1260456d937a4ddef07ccf)
+++ b/equality-explorer/package.json	(date 1710537716211)
@@ -59,6 +59,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../equality-explorer/tsconfig.json"
+          ]
         }
       }
     ]
Index: estimation/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/estimation/package.json b/estimation/package.json
--- a/estimation/package.json	(revision 633731c8318e072015f0cb1b7e09920606da44f8)
+++ b/estimation/package.json	(date 1710537716303)
@@ -28,6 +28,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../estimation/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: example-sim/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/example-sim/package.json b/example-sim/package.json
--- a/example-sim/package.json	(revision 281eb74af0fd422aedadd8b6bce3f272276bc985)
+++ b/example-sim/package.json	(date 1710537716335)
@@ -46,6 +46,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../example-sim/tsconfig.json"
+          ]
         }
       }
     ]
Index: expression-exchange/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/expression-exchange/package.json b/expression-exchange/package.json
--- a/expression-exchange/package.json	(revision e6f2bf628c933dc859fad8c77972bc9c951b5a9f)
+++ b/expression-exchange/package.json	(date 1710537716365)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../expression-exchange/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: faradays-electromagnetic-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/faradays-electromagnetic-lab/package.json b/faradays-electromagnetic-lab/package.json
--- a/faradays-electromagnetic-lab/package.json	(revision 0b31189d5b6a4834896e7c90677d826661fb95d4)
+++ b/faradays-electromagnetic-lab/package.json	(date 1710793403173)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../faradays-electromagnetic-lab/tsconfig.json"
+          ]
         }
       }
     ]
Index: faradays-law/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/faradays-law/package.json b/faradays-law/package.json
--- a/faradays-law/package.json	(revision b8812d5e26f9f2852ce9211990ccaf32fb266472)
+++ b/faradays-law/package.json	(date 1710537716427)
@@ -30,6 +30,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../faradays-law/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fenster/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fenster/package.json b/fenster/package.json
--- a/fenster/package.json	(revision 0ea579907b90032dc4a82576db58ca43449649cb)
+++ b/fenster/package.json	(date 1710537716458)
@@ -37,6 +37,18 @@
     },
     "rules": {
       "todo-should-have-issue": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fenster/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fluid-pressure-and-flow/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fluid-pressure-and-flow/package.json b/fluid-pressure-and-flow/package.json
--- a/fluid-pressure-and-flow/package.json	(revision f0610de399b78e1f42875d26d48ec961e626af65)
+++ b/fluid-pressure-and-flow/package.json	(date 1710537716490)
@@ -31,6 +31,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "globals": {
       "numeric": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fluid-pressure-and-flow/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: forces-and-motion-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/forces-and-motion-basics/package.json b/forces-and-motion-basics/package.json
--- a/forces-and-motion-basics/package.json	(revision 541ebbd672bf4d9771fb60ea698e9581b1e6e16f)
+++ b/forces-and-motion-basics/package.json	(date 1710537716524)
@@ -45,6 +45,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../forces-and-motion-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fourier-making-waves/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fourier-making-waves/package.json b/fourier-making-waves/package.json
--- a/fourier-making-waves/package.json	(revision c426cfecf22c7c4dddb7081ac19a6fc2426789c9)
+++ b/fourier-making-waves/package.json	(date 1710537716556)
@@ -53,6 +53,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../fourier-making-waves/tsconfig.json"
+          ]
         }
       }
     ]
Index: fraction-comparison/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fraction-comparison/package.json b/fraction-comparison/package.json
--- a/fraction-comparison/package.json	(revision ac55a6fef926705c48ca1e8a8cff9437c4dc6e06)
+++ b/fraction-comparison/package.json	(date 1710537716586)
@@ -24,6 +24,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fraction-comparison/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fraction-matcher/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fraction-matcher/package.json b/fraction-matcher/package.json
--- a/fraction-matcher/package.json	(revision fcd7d34c0bb5e0e2e98724df1f3942a47be6e2db)
+++ b/fraction-matcher/package.json	(date 1710537716617)
@@ -33,6 +33,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fraction-matcher/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fractions-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fractions-common/package.json b/fractions-common/package.json
--- a/fractions-common/package.json	(revision fce3a4d906b90c44c21443274f018826d5ee2020)
+++ b/fractions-common/package.json	(date 1710537716648)
@@ -15,6 +15,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fractions-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fractions-equality/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fractions-equality/package.json b/fractions-equality/package.json
--- a/fractions-equality/package.json	(revision 848d280eb657ba4d4b21aae442b7aaad1d22d0ae)
+++ b/fractions-equality/package.json	(date 1710537716678)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fractions-equality/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fractions-intro/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fractions-intro/package.json b/fractions-intro/package.json
--- a/fractions-intro/package.json	(revision b2b1d396a8ac9d313947fe750e69273f645995d5)
+++ b/fractions-intro/package.json	(date 1710537716709)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fractions-intro/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: fractions-mixed-numbers/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/fractions-mixed-numbers/package.json b/fractions-mixed-numbers/package.json
--- a/fractions-mixed-numbers/package.json	(revision 7eeb425da15449ed0468e065780de52a0ec80a28)
+++ b/fractions-mixed-numbers/package.json	(date 1710537716740)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../fractions-mixed-numbers/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: friction/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/friction/package.json b/friction/package.json
--- a/friction/package.json	(revision 42c075a155601dd04f40e1ee8aa644cda48b5fc5)
+++ b/friction/package.json	(date 1710537716771)
@@ -31,6 +31,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../friction/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: function-builder-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/function-builder-basics/package.json b/function-builder-basics/package.json
--- a/function-builder-basics/package.json	(revision d16841dfe9b55db2bb7ac8094a4e38bc77cbe8dc)
+++ b/function-builder-basics/package.json	(date 1710537716834)
@@ -55,6 +55,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../function-builder-basics/tsconfig.json"
+          ]
         }
       }
     ]
Index: function-builder/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/function-builder/package.json b/function-builder/package.json
--- a/function-builder/package.json	(revision ccc86ffe62e0be99433e2f4663aca7779cefd99a)
+++ b/function-builder/package.json	(date 1710537716802)
@@ -58,6 +58,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../function-builder/tsconfig.json"
+          ]
         }
       }
     ]
Index: perennial/js/grunt/Gruntfile.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/perennial/js/grunt/Gruntfile.js b/perennial/js/grunt/Gruntfile.js
--- a/perennial/js/grunt/Gruntfile.js	(revision 63e9458896b1165d59c6908e8c1edb651a53faa3)
+++ b/perennial/js/grunt/Gruntfile.js	(date 1710876160042)
@@ -18,6 +18,9 @@
 const assert = require( 'assert' );
 const _ = require( 'lodash' );
 require( './checkNodeVersion' );
+
+const { spawn } = require( 'child_process' );
+const path = require( 'path' );
 ///////////////////////////
 
 module.exports = function( grunt ) {
@@ -527,32 +530,56 @@
   grunt.registerTask( 'lint-everything', 'lint all js files for all repos', wrapTask( async () => {
     const getDataFile = require( '../common/getDataFile' );
 
-    // --disable-eslint-cache disables the cache, useful for developing rules
-    const cache = !grunt.option( 'disable-eslint-cache' );
     const activeRepos = getDataFile( 'active-repos' );
     const fix = grunt.option( 'fix' );
     const format = grunt.option( 'format' );
     const chipAway = grunt.option( 'chip-away' );
     const disableWithComment = grunt.option( 'disable-with-comment' );
-    const showProgressBar = !grunt.option( 'hide-progress-bar' );
+    const disableEslintCache = grunt.option( 'disable-eslint-cache' );
+
+    const CHUNK_SIZE = 50;
+    const repoChunks = _.chunk( activeRepos, CHUNK_SIZE );
+
+    const errors = [];
+
+    for ( const repoChunk of repoChunks ) {
+      try {
+        await new Promise( ( resolve, reject ) => {
+          const gruntArgs = [ '../chipper/js/grunt/lintMain.js' ];
+
+          fix && gruntArgs.push( '--fix' );
+          format && gruntArgs.push( '--format' );
+          chipAway && gruntArgs.push( '--chip-away' );
+          disableWithComment && gruntArgs.push( '--disable-with-comment' );
+          disableEslintCache && gruntArgs.push( '--disable-eslint-cache' );
+          gruntArgs.push( `--repos=${repoChunk.join( ',' )}` );
 
-    // Don't always require this, as we may have an older chipper checked out.  Also make sure it is the promise-based lint.
-    const lint = require( '../../../chipper/js/grunt/lint' );
-    if ( lint.chipperAPIVersion === 'promisesPerRepo1' ) {
-      const lintReturnValue = await lint( activeRepos, {
-        cache: cache,
-        fix: fix,
-        format: format,
-        chipAway: chipAway,
-        disableWithComment: disableWithComment,
-        showProgressBar: showProgressBar
-      } );
+          console.log( 'running grunt', gruntArgs.join( ' ' ) );
+
+          const childProcess = spawn( 'node', gruntArgs, {
+            stdio: 'inherit'
+          } );
 
-      // Output results on errors.
-      if ( !lintReturnValue.ok ) {
-        grunt.fail.fatal( 'Lint failed' );
+          childProcess.on( 'close', code => {
+            if ( code === 0 ) {
+              resolve();
+            }
+            else {
+              reject( new Error( `Lint failed for repo batch: ${repoChunk}` ) );
+            }
+          } );
+        } );
+      }
+      catch( error ) {
+        console.error( `Lint failed for repo chunk: ${repoChunk}:`, error );
+        errors.push( error );
       }
     }
+
+    console.log( 'lint-everything completed. Errors:', errors.length );
+    if ( errors.length > 0 ) {
+      grunt.fail.fatal( 'lint-everything failed' );
+    }
   } ) );
 
   grunt.registerTask( 'generate-data', 'Generates the lists under perennial/data/, and if there were changes, will commit and push.', wrapTask( async () => {
Index: gas-properties/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gas-properties/package.json b/gas-properties/package.json
--- a/gas-properties/package.json	(revision dd554d705894c6e2837fa6a5d43b83855a48a54d)
+++ b/gas-properties/package.json	(date 1710537716868)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../gas-properties/tsconfig.json"
+          ]
         }
       }
     ]
Index: gases-intro/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gases-intro/package.json b/gases-intro/package.json
--- a/gases-intro/package.json	(revision a26749353c03e5b971a0bc5486904ed2c2b2a3b0)
+++ b/gases-intro/package.json	(date 1710537716899)
@@ -55,6 +55,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../gases-intro/tsconfig.json"
+          ]
         }
       }
     ]
Index: gene-expression-essentials/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gene-expression-essentials/package.json b/gene-expression-essentials/package.json
--- a/gene-expression-essentials/package.json	(revision 4f57d8ffd2e26317367e23d0956aec9af16f19f5)
+++ b/gene-expression-essentials/package.json	(date 1710537716929)
@@ -30,6 +30,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../gene-expression-essentials/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: geometric-optics-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/geometric-optics-basics/package.json b/geometric-optics-basics/package.json
--- a/geometric-optics-basics/package.json	(revision ad2b639b4c2c898a1d569a9589cb03b759074f0c)
+++ b/geometric-optics-basics/package.json	(date 1710537717026)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../geometric-optics-basics/tsconfig.json"
+          ]
         }
       }
     ]
Index: geometric-optics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/geometric-optics/package.json b/geometric-optics/package.json
--- a/geometric-optics/package.json	(revision cd68a79a1dbadae539bcadb24dad84a20755e3c9)
+++ b/geometric-optics/package.json	(date 1710537716993)
@@ -54,6 +54,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../geometric-optics/tsconfig.json"
+          ]
         }
       }
     ]
Index: graphing-lines/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/graphing-lines/package.json b/graphing-lines/package.json
--- a/graphing-lines/package.json	(revision 8b38937fa36095d942a63deb9504dbfd70483c29)
+++ b/graphing-lines/package.json	(date 1710537717057)
@@ -63,6 +63,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../graphing-lines/tsconfig.json"
+          ]
         }
       }
     ]
Index: graphing-quadratics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/graphing-quadratics/package.json b/graphing-quadratics/package.json
--- a/graphing-quadratics/package.json	(revision c2027b1ad2bb1ad1f042c112dd25e82f59344b50)
+++ b/graphing-quadratics/package.json	(date 1710537717087)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../graphing-quadratics/tsconfig.json"
+          ]
         }
       }
     ]
Index: graphing-slope-intercept/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/graphing-slope-intercept/package.json b/graphing-slope-intercept/package.json
--- a/graphing-slope-intercept/package.json	(revision 398cef600b618ae0da347a7e08c14f15bc68f6a5)
+++ b/graphing-slope-intercept/package.json	(date 1710537717118)
@@ -62,6 +62,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../graphing-slope-intercept/tsconfig.json"
+          ]
         }
       }
     ]
Index: buoyancy-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/buoyancy-basics/package.json b/buoyancy-basics/package.json
--- a/buoyancy-basics/package.json	(revision 7b8092e21053bca1deff611786619cbdb16ea1d8)
+++ b/buoyancy-basics/package.json	(date 1710537715317)
@@ -26,7 +26,6 @@
       "phet",
       "adapted-from-phet"
     ],
-
     "supportsOutputJS": true,
     "simFeatures": {
       "supportsDynamicLocale": true
@@ -49,6 +48,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../buoyancy-basics/tsconfig.json"
+          ]
         }
       }
     ]
Index: gravity-and-orbits/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gravity-and-orbits/package.json b/gravity-and-orbits/package.json
--- a/gravity-and-orbits/package.json	(revision 910b0141738a458e7498765e0a62886ff9fbc5f1)
+++ b/gravity-and-orbits/package.json	(date 1710537717149)
@@ -36,6 +36,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../gravity-and-orbits/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: gravity-force-lab-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gravity-force-lab-basics/package.json b/gravity-force-lab-basics/package.json
--- a/gravity-force-lab-basics/package.json	(revision 325b40c660ee84fe0568419074200c8f9cbab540)
+++ b/gravity-force-lab-basics/package.json	(date 1710537717211)
@@ -32,6 +32,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../gravity-force-lab-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: gravity-force-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gravity-force-lab/package.json b/gravity-force-lab/package.json
--- a/gravity-force-lab/package.json	(revision 79198b721033c6e9e383243ab1ac278d61562c2d)
+++ b/gravity-force-lab/package.json	(date 1710537717180)
@@ -33,6 +33,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../gravity-force-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: greenhouse-effect/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/greenhouse-effect/package.json b/greenhouse-effect/package.json
--- a/greenhouse-effect/package.json	(revision 9215a9ce3936fcecd3255880270e7250b1582840)
+++ b/greenhouse-effect/package.json	(date 1710537717241)
@@ -40,6 +40,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../greenhouse-effect/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: griddle/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/griddle/package.json b/griddle/package.json
--- a/griddle/package.json	(revision bb9d24375a71eb005551298b99c2a85b13f6504c)
+++ b/griddle/package.json	(date 1710537717272)
@@ -23,6 +23,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../griddle/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: hookes-law/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/hookes-law/package.json b/hookes-law/package.json
--- a/hookes-law/package.json	(revision 2079202a719eeeff132dbbd3eadbb2daad486544)
+++ b/hookes-law/package.json	(date 1710537717303)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../hookes-law/tsconfig.json"
+          ]
         }
       }
     ]
Index: interaction-dashboard/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/interaction-dashboard/package.json b/interaction-dashboard/package.json
--- a/interaction-dashboard/package.json	(revision 8214f0a2ca86ede24355136167cf6a6ca42f0f1b)
+++ b/interaction-dashboard/package.json	(date 1710537717335)
@@ -32,6 +32,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../interaction-dashboard/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: inverse-square-law-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/inverse-square-law-common/package.json b/inverse-square-law-common/package.json
--- a/inverse-square-law-common/package.json	(revision 6e7fadfe4cab2967f3e88605d221a0f5b43eeea9)
+++ b/inverse-square-law-common/package.json	(date 1710537717365)
@@ -14,6 +14,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../inverse-square-law-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: isotopes-and-atomic-mass/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/isotopes-and-atomic-mass/package.json b/isotopes-and-atomic-mass/package.json
--- a/isotopes-and-atomic-mass/package.json	(revision d98dff8f4502850e3346859cbf974d8f821d99e4)
+++ b/isotopes-and-atomic-mass/package.json	(date 1710537717395)
@@ -28,6 +28,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../isotopes-and-atomic-mass/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: john-travoltage/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/john-travoltage/package.json b/john-travoltage/package.json
--- a/john-travoltage/package.json	(revision ca13d4dbf2dee1a8262d2c73958e8e165290f124)
+++ b/john-travoltage/package.json	(date 1710537717427)
@@ -37,6 +37,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../john-travoltage/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: joist/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/joist/package.json b/joist/package.json
--- a/joist/package.json	(revision ba28dcc7e2b110c80f47a4de0498c8caa2333c39)
+++ b/joist/package.json	(date 1710537717457)
@@ -32,6 +32,18 @@
     },
     "rules": {
       "template-curly-spacing": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../joist/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-vite-demo/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-vite-demo/package.json b/phet-vite-demo/package.json
--- a/phet-vite-demo/package.json	(revision a7edd9c3ad8fcde25974ce920db931a85837bcbd)
+++ b/phet-vite-demo/package.json	(date 1710542933568)
@@ -18,7 +18,6 @@
     "@typescript-eslint/parser": "~6.18.1",
     "@typescript-eslint/eslint-plugin": "~6.18.1",
     "@typescript-eslint/utils": "~6.18.1",
-
     "@types/jquery": "~3.5.13",
     "@types/lodash": "~4.14.172",
     "@types/p2": "~0.7.39",
Index: keplers-laws/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/keplers-laws/package.json b/keplers-laws/package.json
--- a/keplers-laws/package.json	(revision 8303e79c772cb3115672941706ffc1887253677c)
+++ b/keplers-laws/package.json	(date 1710537717488)
@@ -61,6 +61,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../keplers-laws/tsconfig.json"
+          ]
         }
       }
     ]
Index: kite/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/kite/package.json b/kite/package.json
--- a/kite/package.json	(revision bb6d7e60fc313e358b17861efce2054c78d74ed6)
+++ b/kite/package.json	(date 1710537717518)
@@ -25,6 +25,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../kite/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: least-squares-regression/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/least-squares-regression/package.json b/least-squares-regression/package.json
--- a/least-squares-regression/package.json	(revision 41594cdd121dc90b583c232e0dcf43865d8b4a44)
+++ b/least-squares-regression/package.json	(date 1710537717549)
@@ -24,6 +24,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../least-squares-regression/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: make-a-ten/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/make-a-ten/package.json b/make-a-ten/package.json
--- a/make-a-ten/package.json	(revision cdd4504852fa769f4a808a271c1b1cc82d1ea61c)
+++ b/make-a-ten/package.json	(date 1710540840224)
@@ -47,6 +47,16 @@
         "rules": {
           "author-annotation": "error"
         }
+      },
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../make-a-ten/tsconfig.json"
+          ]
+        }
       }
     ]
   }
Index: masses-and-springs-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/masses-and-springs-basics/package.json b/masses-and-springs-basics/package.json
--- a/masses-and-springs-basics/package.json	(revision dd97f2782456d54f933dd1a812b2cb46542d46e6)
+++ b/masses-and-springs-basics/package.json	(date 1710537717702)
@@ -37,6 +37,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../masses-and-springs-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: masses-and-springs/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/masses-and-springs/package.json b/masses-and-springs/package.json
--- a/masses-and-springs/package.json	(revision be06fe45317f9c26a3585a4429afd723b85d27c6)
+++ b/masses-and-springs/package.json	(date 1710537717671)
@@ -41,6 +41,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../masses-and-springs/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: mean-share-and-balance/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/mean-share-and-balance/package.json b/mean-share-and-balance/package.json
--- a/mean-share-and-balance/package.json	(revision 8417490d2e5cabb7a15eb2f0db86624b6c8497fd)
+++ b/mean-share-and-balance/package.json	(date 1710537717732)
@@ -38,6 +38,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../mean-share-and-balance/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: mobius/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/mobius/package.json b/mobius/package.json
--- a/mobius/package.json	(revision 0498be081336646617df9eadced6de263546a75b)
+++ b/mobius/package.json	(date 1710537717763)
@@ -28,6 +28,18 @@
     "extends": "../chipper/eslint/phet-library_eslintrc.js",
     "globals": {
       "THREE": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../mobius/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: models-of-the-hydrogen-atom/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/models-of-the-hydrogen-atom/package.json b/models-of-the-hydrogen-atom/package.json
--- a/models-of-the-hydrogen-atom/package.json	(revision f6b0761ec8af87c2e4fbe4e5b710bad0f45bec5e)
+++ b/models-of-the-hydrogen-atom/package.json	(date 1710537717793)
@@ -53,6 +53,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../models-of-the-hydrogen-atom/tsconfig.json"
+          ]
         }
       }
     ]
Index: molarity/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/molarity/package.json b/molarity/package.json
--- a/molarity/package.json	(revision 8b87b61d76003e9111e8ffacfc1c7e9af3c40775)
+++ b/molarity/package.json	(date 1710537717824)
@@ -29,6 +29,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../molarity/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: molecule-polarity/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/molecule-polarity/package.json b/molecule-polarity/package.json
--- a/molecule-polarity/package.json	(revision e9610d79b9ada0f3ce9676c878531944f8d7aba5)
+++ b/molecule-polarity/package.json	(date 1710537717854)
@@ -55,6 +55,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../molecule-polarity/tsconfig.json"
+          ]
         }
       }
     ]
Index: molecule-shapes-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/molecule-shapes-basics/package.json b/molecule-shapes-basics/package.json
--- a/molecule-shapes-basics/package.json	(revision dae1d92e84658d33a49a02899d3b3dd851c8a6fc)
+++ b/molecule-shapes-basics/package.json	(date 1710537717915)
@@ -47,6 +47,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../molecule-shapes-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: molecule-shapes/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/molecule-shapes/package.json b/molecule-shapes/package.json
--- a/molecule-shapes/package.json	(revision 6ba51ab05ff9bd3ae6d5ee7933eba6fd65a3b7b3)
+++ b/molecule-shapes/package.json	(date 1710537717885)
@@ -52,6 +52,18 @@
     },
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../molecule-shapes/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: molecules-and-light/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/molecules-and-light/package.json b/molecules-and-light/package.json
--- a/molecules-and-light/package.json	(revision 9d092629f4f26f8d47904822696abc02dd3c9475)
+++ b/molecules-and-light/package.json	(date 1710537717947)
@@ -30,6 +30,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../molecules-and-light/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: monday/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/monday/package.json b/monday/package.json
--- a/monday/package.json	(revision a46a6d9e95ee291500d488d6f83c786a69647e22)
+++ b/monday/package.json	(date 1710537717978)
@@ -28,6 +28,18 @@
           ]
         }
       ]
-    }
-  }
-}
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../monday/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: my-solar-system/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/my-solar-system/package.json b/my-solar-system/package.json
--- a/my-solar-system/package.json	(revision 6805d8aaa9f60a2abb72bb38cc39b7190909e144)
+++ b/my-solar-system/package.json	(date 1710537718010)
@@ -43,6 +43,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../my-solar-system/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: natural-selection/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/natural-selection/package.json b/natural-selection/package.json
--- a/natural-selection/package.json	(revision 51f25abc46d2d903283a3893a6fe0da929aa8ca3)
+++ b/natural-selection/package.json	(date 1710537718042)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../natural-selection/tsconfig.json"
+          ]
         }
       }
     ]
Index: neuron/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/neuron/package.json b/neuron/package.json
--- a/neuron/package.json	(revision ad28b65b1b09d2a9b2db158c49cd178c19970c55)
+++ b/neuron/package.json	(date 1710537718072)
@@ -24,6 +24,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../neuron/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: nitroglycerin/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/nitroglycerin/package.json b/nitroglycerin/package.json
--- a/nitroglycerin/package.json	(revision a563204800f63d0d675a29fc0624e0e5209ce2bb)
+++ b/nitroglycerin/package.json	(date 1710537718103)
@@ -22,6 +22,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../nitroglycerin/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: normal-modes/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/normal-modes/package.json b/normal-modes/package.json
--- a/normal-modes/package.json	(revision e14ca908d3b5d18822777eb1dee84bf96c43c9cf)
+++ b/normal-modes/package.json	(date 1710537718134)
@@ -24,6 +24,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../normal-modes/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-compare/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-compare/package.json b/number-compare/package.json
--- a/number-compare/package.json	(revision afce05f393eb9137c9ac0bc4dc01630b983b7cf6)
+++ b/number-compare/package.json	(date 1710537718165)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-compare/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-line-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-line-common/package.json b/number-line-common/package.json
--- a/number-line-common/package.json	(revision 825c02eae3e0b235fd9774c177e411d8a828a664)
+++ b/number-line-common/package.json	(date 1710537718196)
@@ -17,6 +17,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-line-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-line-distance/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-line-distance/package.json b/number-line-distance/package.json
--- a/number-line-distance/package.json	(revision 99073940cd7b8a7ca562f30a1a199ba496b44945)
+++ b/number-line-distance/package.json	(date 1710537718227)
@@ -41,6 +41,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-line-distance/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-line-integers/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-line-integers/package.json b/number-line-integers/package.json
--- a/number-line-integers/package.json	(revision 2e17ca0f77e2b8cc19962de5f228f674ced9ec61)
+++ b/number-line-integers/package.json	(date 1710537718257)
@@ -42,6 +42,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-line-integers/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-line-operations/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-line-operations/package.json b/number-line-operations/package.json
--- a/number-line-operations/package.json	(revision 66f1ad839442fc8894b42170e2415373a5771366)
+++ b/number-line-operations/package.json	(date 1710537718288)
@@ -34,6 +34,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-line-operations/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-play/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-play/package.json b/number-play/package.json
--- a/number-play/package.json	(revision c9e3591450a8492255a28489107e0fd085893183)
+++ b/number-play/package.json	(date 1710537718319)
@@ -40,6 +40,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-play/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: number-suite-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/number-suite-common/package.json b/number-suite-common/package.json
--- a/number-suite-common/package.json	(revision 68280e0d9ce1d79b32b4ff51be00f9e9402cb241)
+++ b/number-suite-common/package.json	(date 1710537718349)
@@ -24,6 +24,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../number-suite-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: ohms-law/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ohms-law/package.json b/ohms-law/package.json
--- a/ohms-law/package.json	(revision 63587b5c2c233bee48a51c3790cac6e31d0d24e7)
+++ b/ohms-law/package.json	(date 1710537718380)
@@ -26,6 +26,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../ohms-law/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: optics-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/optics-lab/package.json b/optics-lab/package.json
--- a/optics-lab/package.json	(revision efe0891b6196c2df87c59aa12c0f8048e0bb3e24)
+++ b/optics-lab/package.json	(date 1710537718411)
@@ -20,6 +20,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../optics-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: pendulum-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/pendulum-lab/package.json b/pendulum-lab/package.json
--- a/pendulum-lab/package.json	(revision 758f1d91ca18a82b00bd381d8f6bd42e8f377483)
+++ b/pendulum-lab/package.json	(date 1710537718441)
@@ -32,6 +32,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../pendulum-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: perennial-alias/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/perennial-alias/package.json b/perennial-alias/package.json
--- a/perennial-alias/package.json	(revision 63e9458896b1165d59c6908e8c1edb651a53faa3)
+++ b/perennial-alias/package.json	(date 1710537718503)
@@ -35,10 +35,22 @@
     "xml2js": "~0.4.15"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/node_eslintrc.js"
+    "extends": "../chipper/eslint/node_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../perennial-alias/tsconfig.json"
+          ]
+        }
+      }
+    ]
   },
   "dependencies": {
     "nodemailer": "^6.9.1",
     "pug": "^3.0.2"
   }
-}
+}
\ No newline at end of file
Index: perennial/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/perennial/package.json b/perennial/package.json
--- a/perennial/package.json	(revision 63e9458896b1165d59c6908e8c1edb651a53faa3)
+++ b/perennial/package.json	(date 1710537718472)
@@ -35,10 +35,22 @@
     "xml2js": "~0.4.15"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/node_eslintrc.js"
+    "extends": "../chipper/eslint/node_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../perennial/tsconfig.json"
+          ]
+        }
+      }
+    ]
   },
   "dependencies": {
     "nodemailer": "^6.9.1",
     "pug": "^3.0.2"
   }
-}
+}
\ No newline at end of file
Index: ph-scale-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ph-scale-basics/package.json b/ph-scale-basics/package.json
--- a/ph-scale-basics/package.json	(revision e6234d3443bcbfbb660515a445d97d5fe590d580)
+++ b/ph-scale-basics/package.json	(date 1710537718564)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../ph-scale-basics/tsconfig.json"
+          ]
         }
       }
     ]
Index: ph-scale/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ph-scale/package.json b/ph-scale/package.json
--- a/ph-scale/package.json	(revision efc3e71bacebf6b4dc604fbd06b01c94711446ee)
+++ b/ph-scale/package.json	(date 1710537718533)
@@ -55,6 +55,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../ph-scale/tsconfig.json"
+          ]
         }
       }
     ]
Index: phet-core/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-core/package.json b/phet-core/package.json
--- a/phet-core/package.json	(revision 88a3c35ad4e7e20f08af728e5bfd0f19dba1aaba)
+++ b/phet-core/package.json	(date 1710537718595)
@@ -15,6 +15,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-core/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-info/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-info/package.json b/phet-info/package.json
--- a/phet-info/package.json	(revision 13b9f0fd35dc415fdf1143e068e449bfc700bf10)
+++ b/phet-info/package.json	(date 1710537718626)
@@ -8,5 +8,19 @@
   },
   "devDependencies": {
     "octokit": "^3.1.2"
+  },
+  "eslintConfig": {
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-info/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-sim-specific/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-sim-specific/package.json b/phet-io-sim-specific/package.json
--- a/phet-io-sim-specific/package.json	(revision 10865b918a529afee3c954aff3c896706e82158c)
+++ b/phet-io-sim-specific/package.json	(date 1710537718716)
@@ -23,6 +23,16 @@
         "rules": {
           "copyright": "off"
         }
+      },
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-sim-specific/tsconfig.json"
+          ]
+        }
       }
     ]
   }
Index: phet-io-test-sim/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-test-sim/package.json b/phet-io-test-sim/package.json
--- a/phet-io-test-sim/package.json	(revision 5ec7027c0aca8a56f24c34d4cd1b911429b2dc38)
+++ b/phet-io-test-sim/package.json	(date 1710537718747)
@@ -24,6 +24,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-test-sim/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-wrapper-classroom-activity/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-wrapper-classroom-activity/package.json b/phet-io-wrapper-classroom-activity/package.json
--- a/phet-io-wrapper-classroom-activity/package.json	(revision 9d20802a1543481b5421e902ca006acbe82f3aea)
+++ b/phet-io-wrapper-classroom-activity/package.json	(date 1710537718808)
@@ -10,6 +10,18 @@
     "grunt": "~1.5.3"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/.eslintrc.js"
+    "extends": "../chipper/eslint/.eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-wrapper-classroom-activity/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-wrapper-haptics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-wrapper-haptics/package.json b/phet-io-wrapper-haptics/package.json
--- a/phet-io-wrapper-haptics/package.json	(revision a146c1d416f669a28ca34619a08f5e7085b2bcbf)
+++ b/phet-io-wrapper-haptics/package.json	(date 1710537718840)
@@ -16,6 +16,18 @@
     "phetLibs": []
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/.eslintrc.js"
+    "extends": "../chipper/eslint/.eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-wrapper-haptics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-wrapper-hookes-law-energy/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-wrapper-hookes-law-energy/package.json b/phet-io-wrapper-hookes-law-energy/package.json
--- a/phet-io-wrapper-hookes-law-energy/package.json	(revision bce253c895e83df41056ea4bcb68c61048396707)
+++ b/phet-io-wrapper-hookes-law-energy/package.json	(date 1710537718870)
@@ -7,6 +7,18 @@
     "url": "https://github.com/phetsims/phet-io-wrapper-hookes-law.git"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/.eslintrc.js"
+    "extends": "../chipper/eslint/.eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-wrapper-hookes-law-energy/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-wrapper-lab-book/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-wrapper-lab-book/package.json b/phet-io-wrapper-lab-book/package.json
--- a/phet-io-wrapper-lab-book/package.json	(revision 6fa2ef459a5ace096caee8fb72f502b6e7e3bd31)
+++ b/phet-io-wrapper-lab-book/package.json	(date 1710537718901)
@@ -13,6 +13,18 @@
     "extends": "../chipper/eslint/.eslintrc.js",
     "globals": {
       "d3": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-wrapper-lab-book/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-io-wrappers/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io-wrappers/package.json b/phet-io-wrappers/package.json
--- a/phet-io-wrappers/package.json	(revision a374bab9fd0604c3d3d324e329ac7f815a9b3022)
+++ b/phet-io-wrappers/package.json	(date 1710537718932)
@@ -28,6 +28,16 @@
         "rules": {
           "no-new": "off"
         }
+      },
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io-wrappers/tsconfig.json"
+          ]
+        }
       }
     ],
     "globals": {
Index: phet-io/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-io/package.json b/phet-io/package.json
--- a/phet-io/package.json	(revision 3e59e1effe8d1646cf92ca39835487aa1a01098f)
+++ b/phet-io/package.json	(date 1710537718656)
@@ -15,6 +15,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-io/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phet-lib/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phet-lib/package.json b/phet-lib/package.json
--- a/phet-lib/package.json	(revision 640f8a570508436357b697802a52a891eec6f665)
+++ b/phet-lib/package.json	(date 1710537718963)
@@ -116,6 +116,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
-  }
-}
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phet-lib/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: phetcommon/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phetcommon/package.json b/phetcommon/package.json
--- a/phetcommon/package.json	(revision 92535c7f8a9739a52821269939d4b39d4e2d8e2d)
+++ b/phetcommon/package.json	(date 1710537719027)
@@ -15,6 +15,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phetcommon/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phetmarks/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phetmarks/package.json b/phetmarks/package.json
--- a/phetmarks/package.json	(revision 24d75ba3359b4e9af1a33085c9688fb877d54814)
+++ b/phetmarks/package.json	(date 1710537719057)
@@ -10,6 +10,18 @@
     "grunt": "~1.5.3"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/.eslintrc.js"
+    "extends": "../chipper/eslint/.eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phetmarks/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: phettest/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/phettest/package.json b/phettest/package.json
--- a/phettest/package.json	(revision aba6dff298c7dd5c256373e1d9e5c7adaeee6b44)
+++ b/phettest/package.json	(date 1710537719088)
@@ -10,6 +10,18 @@
     "grunt": "~1.5.3"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/.eslintrc.js"
+    "extends": "../chipper/eslint/.eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../phettest/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: plinko-probability/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/plinko-probability/package.json b/plinko-probability/package.json
--- a/plinko-probability/package.json	(revision b9bd81b384c49ba23473ff9d2813e00cdff42012)
+++ b/plinko-probability/package.json	(date 1710537719118)
@@ -28,6 +28,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../plinko-probability/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: projectile-data-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/projectile-data-lab/package.json b/projectile-data-lab/package.json
--- a/projectile-data-lab/package.json	(revision 462491442a63972e61daa77d308521570a21917a)
+++ b/projectile-data-lab/package.json	(date 1710537719180)
@@ -64,6 +64,11 @@
               ]
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../projectile-data-lab/tsconfig.json"
+          ]
         }
       }
     ]
Index: projectile-motion/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/projectile-motion/package.json b/projectile-motion/package.json
--- a/projectile-motion/package.json	(revision 9260962df656a4526acb0428110773663d8f95c4)
+++ b/projectile-motion/package.json	(date 1710537719149)
@@ -40,6 +40,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../projectile-motion/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: proportion-playground/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/proportion-playground/package.json b/proportion-playground/package.json
--- a/proportion-playground/package.json	(revision cbae9d22227e5387bbce53030a7d9704dcb54cdc)
+++ b/proportion-playground/package.json	(date 1710537719211)
@@ -26,6 +26,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../proportion-playground/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: quadrilateral/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/quadrilateral/package.json b/quadrilateral/package.json
--- a/quadrilateral/package.json	(revision 4c92500974704504a0df6199b0828de47b2908ff)
+++ b/quadrilateral/package.json	(date 1710537719271)
@@ -34,6 +34,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../quadrilateral/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: quake/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/quake/package.json b/quake/package.json
--- a/quake/package.json	(revision e415b9d344a3c38117cc28206e1594c53404c4ff)
+++ b/quake/package.json	(date 1710542695990)
@@ -43,7 +43,8 @@
     "extends": "../chipper/eslint/node_eslintrc.js",
     "ignorePatterns": [
       "platforms/",
-      "plugins/"
+      "plugins/",
+      "**/*.d.ts"
     ],
     "globals": {
       "alert": "readonly",
Index: query-string-machine/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/query-string-machine/package.json b/query-string-machine/package.json
--- a/query-string-machine/package.json	(revision 4c858545eaaaf80533682c22b74a01adc7aa6bb2)
+++ b/query-string-machine/package.json	(date 1710537719332)
@@ -13,6 +13,18 @@
     "generatedUnitTests": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../query-string-machine/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: ratio-and-proportion/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ratio-and-proportion/package.json b/ratio-and-proportion/package.json
--- a/ratio-and-proportion/package.json	(revision 29355f992ae45acef5f005c325c7df50c96c07c9)
+++ b/ratio-and-proportion/package.json	(date 1710537719363)
@@ -41,6 +41,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../ratio-and-proportion/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: reactants-products-and-leftovers/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/reactants-products-and-leftovers/package.json b/reactants-products-and-leftovers/package.json
--- a/reactants-products-and-leftovers/package.json	(revision c98ce7688634cb4a2453e6106448e278085e6f8e)
+++ b/reactants-products-and-leftovers/package.json	(date 1710537719394)
@@ -57,6 +57,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../reactants-products-and-leftovers/tsconfig.json"
+          ]
         }
       }
     ]
Index: resistance-in-a-wire/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/resistance-in-a-wire/package.json b/resistance-in-a-wire/package.json
--- a/resistance-in-a-wire/package.json	(revision 3cd0e7feb4397f2cbbda8202d824c9bd240146c0)
+++ b/resistance-in-a-wire/package.json	(date 1710537719425)
@@ -26,6 +26,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../resistance-in-a-wire/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: rosetta/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/rosetta/package.json b/rosetta/package.json
--- a/rosetta/package.json	(revision 054f4be97618478b767ba19a0163562aacce058a)
+++ b/rosetta/package.json	(date 1710537719455)
@@ -25,5 +25,19 @@
     "eslint": "^8.34.0",
     "grunt": "^1.4.1",
     "winston": "^3.8.2"
-  }
-}
+  },
+  "eslintConfig": {
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../rosetta/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: rutherford-scattering/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/rutherford-scattering/package.json b/rutherford-scattering/package.json
--- a/rutherford-scattering/package.json	(revision add3eec7ac74bf2aae12025d30d161826fc57443)
+++ b/rutherford-scattering/package.json	(date 1710537719486)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../rutherford-scattering/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: scenery-phet/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery-phet/package.json b/scenery-phet/package.json
--- a/scenery-phet/package.json	(revision a855464a49c316e505d8eb571ba0e978f46e50c1)
+++ b/scenery-phet/package.json	(date 1710537719579)
@@ -60,6 +60,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../scenery-phet/tsconfig.json"
+          ]
         }
       }
     ],
Index: scenery/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/package.json b/scenery/package.json
--- a/scenery/package.json	(revision 131daef9d8f0aa1fb70370ee1fedbd5cc8d873b6)
+++ b/scenery/package.json	(date 1710537719517)
@@ -36,6 +36,18 @@
       "LineBreaker": "readonly",
       "sceneryLog": "readonly",
       "he": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../scenery/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: sherpa/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sherpa/package.json b/sherpa/package.json
--- a/sherpa/package.json	(revision 1af6d2f2e908c7b4261c0c51a6e15b70b2db0fe3)
+++ b/sherpa/package.json	(date 1710537719609)
@@ -21,6 +21,18 @@
       "js/fontawesome-4/",
       "js/fontawesome-5/",
       "js/fontawesome-5/brands/"
+    ],
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../sherpa/tsconfig.json"
+          ]
+        }
+      }
     ]
   }
 }
\ No newline at end of file
Index: shred/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/shred/package.json b/shred/package.json
--- a/shred/package.json	(revision 1f0c279f6a53f57b6ae46d69071f833a452dc04f)
+++ b/shred/package.json	(date 1710537719640)
@@ -14,6 +14,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../shred/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: simula-rasa/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/simula-rasa/package.json b/simula-rasa/package.json
--- a/simula-rasa/package.json	(revision 93bc4373cbb5b2d19d526e75ca9cbf084ab6a7fe)
+++ b/simula-rasa/package.json	(date 1710537719672)
@@ -40,6 +40,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../simula-rasa/tsconfig.json"
+          ]
         }
       }
     ]
Index: skiffle/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/skiffle/package.json b/skiffle/package.json
--- a/skiffle/package.json	(revision dd9ad37c6778147ecd28b7855e33407f07e763cd)
+++ b/skiffle/package.json	(date 1710537719703)
@@ -16,6 +16,18 @@
     "extends": "../chipper/eslint/node_eslintrc.js",
     "globals": {
       "skiffle": "readonly"
-    }
-  }
-}
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../skiffle/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: soccer-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/soccer-common/package.json b/soccer-common/package.json
--- a/soccer-common/package.json	(revision 92a8294c063adfd2495ee33cc55c9b213fc2d89c)
+++ b/soccer-common/package.json	(date 1710537719735)
@@ -45,6 +45,11 @@
               ]
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../soccer-common/tsconfig.json"
+          ]
         }
       }
     ]
Index: solar-system-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/solar-system-common/package.json b/solar-system-common/package.json
--- a/solar-system-common/package.json	(revision 39ca29afc33d86e9acd9b7efa6cd484ffdb7e1ce)
+++ b/solar-system-common/package.json	(date 1710537719765)
@@ -18,6 +18,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../solar-system-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: sound-waves/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sound-waves/package.json b/sound-waves/package.json
--- a/sound-waves/package.json	(revision 36056aca59fda747a5760105f62c534ede5abe4b)
+++ b/sound-waves/package.json	(date 1710537719795)
@@ -32,6 +32,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../sound-waves/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: states-of-matter-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/states-of-matter-basics/package.json b/states-of-matter-basics/package.json
--- a/states-of-matter-basics/package.json	(revision 84bcb79065bb7b2f02c8ab956eeaa8d0c48b0f49)
+++ b/states-of-matter-basics/package.json	(date 1710537719856)
@@ -36,6 +36,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../states-of-matter-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: states-of-matter/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/states-of-matter/package.json b/states-of-matter/package.json
--- a/states-of-matter/package.json	(revision 099b495c7bf0bd4b57888902ee7126d7d2afdb0e)
+++ b/states-of-matter/package.json	(date 1710537719826)
@@ -36,6 +36,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../states-of-matter/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: studio/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/studio/package.json b/studio/package.json
--- a/studio/package.json	(revision ea41b45429265bf5a2a8946334cf33b12a97480b)
+++ b/studio/package.json	(date 1710537719887)
@@ -27,6 +27,18 @@
       "d3": "readonly",
       "Metacog": "readonly",
       "Chart": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../studio/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: chipper/js/grunt/lintMain.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/js/grunt/lintMain.js b/chipper/js/grunt/lintMain.js
new file mode 100644
--- /dev/null	(date 1710875517417)
+++ b/chipper/js/grunt/lintMain.js	(date 1710875517417)
@@ -0,0 +1,72 @@
+// Copyright 2024, University of Colorado Boulder
+
+/**
+ * Run lint from the command line
+ *
+ * @author Sam Reid (PhET Interactive Simulations)
+ */
+
+
+// // Get the command line arguments
+// const commandLineArguments = process.argv.slice( 2 );
+//
+// // get the repos from the command line arguments
+// const reposArgs = commandLineArguments.filter( commandLineArg => commandLineArg.startsWith( '--repos=' ) );
+//
+// if ( reposArgs.length !== 1 ) {
+//   throw new Error( 'expected exactly one --repos argument' );
+// }
+//
+// const repos = reposArgs[ 0 ].split( '=' )[ 1 ].split( ',' );
+//
+// console.log( repos.join( ' -- ' ) );
+
+
+const lint = require( './lint' );
+
+// Get the command line arguments
+const commandLineArguments = process.argv.slice( 2 );
+
+// Helper function to check if an argument was provided
+const hasArg = argName => commandLineArguments.some( arg => arg === argName );
+
+// Helper function to get the value of an argument
+const getArgValue = argName => {
+  const arg = commandLineArguments.find( arg => arg.startsWith( `${argName}=` ) );
+  return arg ? arg.split( '=' )[ 1 ] : undefined;
+};
+
+// Parsing options from the command line arguments
+const options = {
+  cache: !hasArg( '--disable-eslint-cache' ), // If --disable-eslint-cache is present, cache is false
+  fix: hasArg( '--fix' ),
+  format: hasArg( '--format' ),
+  chipAway: hasArg( '--chip-away' ),
+  disableWithComment: hasArg( '--disable-with-comment' ),
+  repos: getArgValue( '--repos' ) ? getArgValue( '--repos' ).split( ',' ) : []
+};
+
+// Debugging: Log the parsed options
+console.log( 'Options:', options );
+
+// Execute the main task within wrapTask
+
+( async () => {
+
+  try {
+    const lintReturnValue = await lint( options.repos, {
+      cache: options.cache,
+      fix: options.fix,
+      format: options.format,
+      chipAway: options.chipAway,
+      disableWithComment: options.disableWithComment
+    } );
+
+    // Handle the lintReturnValue as needed
+    console.log( 'Linting completed: ok=', lintReturnValue.ok );
+  }
+  catch( e ) {
+
+    console.error( 'Error:', e );
+  }
+} )();
Index: sun/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/package.json b/sun/package.json
--- a/sun/package.json	(revision 921e7790ae261158f0f26bb9978c50fb17a203ed)
+++ b/sun/package.json	(date 1710537719918)
@@ -37,6 +37,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../sun/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: tambo/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/tambo/package.json b/tambo/package.json
--- a/tambo/package.json	(revision fbc86164279b656acea298d7d17941876ea3a518)
+++ b/tambo/package.json	(date 1710537719948)
@@ -33,6 +33,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../tambo/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: tandem/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/tandem/package.json b/tandem/package.json
--- a/tandem/package.json	(revision 074163eafcec63c24e0ecf287e6d491953885ccc)
+++ b/tandem/package.json	(date 1710537719979)
@@ -19,6 +19,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../tandem/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: tangible/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/tangible/package.json b/tangible/package.json
--- a/tangible/package.json	(revision 8c0bccebc68b830482801b969eeb0381bed5c0a6)
+++ b/tangible/package.json	(date 1710537720011)
@@ -20,6 +20,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "globals": {
       "mediaPipeDependencies": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../tangible/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: tappi/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/tappi/package.json b/tappi/package.json
--- a/tappi/package.json	(revision ed3051e6e2946de3328d8ce2e32c1d5a52679653)
+++ b/tappi/package.json	(date 1710537720042)
@@ -33,6 +33,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "todo-should-have-issue": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../tappi/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: trig-tour/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/trig-tour/package.json b/trig-tour/package.json
--- a/trig-tour/package.json	(revision ab489f3f39b87704773fc6d4ea1c0cc620f92d28)
+++ b/trig-tour/package.json	(date 1710537720101)
@@ -21,6 +21,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../trig-tour/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: twixt/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/twixt/package.json b/twixt/package.json
--- a/twixt/package.json	(revision 70e8efd3d395fe0955290c755ded7175d095aca6)
+++ b/twixt/package.json	(date 1710537720131)
@@ -28,6 +28,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../twixt/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: under-pressure/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/under-pressure/package.json b/under-pressure/package.json
--- a/under-pressure/package.json	(revision bbf183e80fc8991b1d863f15eddd8263f08985ee)
+++ b/under-pressure/package.json	(date 1710537720162)
@@ -24,6 +24,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../under-pressure/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: unit-rates/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/unit-rates/package.json b/unit-rates/package.json
--- a/unit-rates/package.json	(revision 71f904d23200e24e3da8db5859ed57fa149711b0)
+++ b/unit-rates/package.json	(date 1710537720193)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../unit-rates/tsconfig.json"
+          ]
         }
       }
     ]
Index: utterance-queue/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/utterance-queue/package.json b/utterance-queue/package.json
--- a/utterance-queue/package.json	(revision be32a7ec583aa553cfe55c9cb4f02a2a8bcb7258)
+++ b/utterance-queue/package.json	(date 1710537720223)
@@ -25,6 +25,18 @@
       "SpeechSynthesis": "readonly",
       "SpeechSynthesisVoice": "readonly",
       "SpeechSynthesisUtterance": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../utterance-queue/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: vector-addition-equations/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/vector-addition-equations/package.json b/vector-addition-equations/package.json
--- a/vector-addition-equations/package.json	(revision 4e0006cef5447bd0edd7189cc562af315630da69)
+++ b/vector-addition-equations/package.json	(date 1710537720284)
@@ -47,6 +47,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../vector-addition-equations/tsconfig.json"
+          ]
         }
       }
     ]
Index: vector-addition/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/vector-addition/package.json b/vector-addition/package.json
--- a/vector-addition/package.json	(revision 0689452d87a14e1a6d18010f2caad70a639454ac)
+++ b/vector-addition/package.json	(date 1710537720253)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../vector-addition/tsconfig.json"
+          ]
         }
       }
     ]
Index: vegas/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/vegas/package.json b/vegas/package.json
--- a/vegas/package.json	(revision c2c73d2ce9b305fc2f61d8b129848d1ee6d678c2)
+++ b/vegas/package.json	(date 1710537720315)
@@ -45,6 +45,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../vegas/tsconfig.json"
+          ]
         }
       }
     ]
Index: vibe/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/vibe/package.json b/vibe/package.json
--- a/vibe/package.json	(revision bca4db05e20a81b34c8cfe2e09a65014be930734)
+++ b/vibe/package.json	(date 1710537720345)
@@ -19,6 +19,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../vibe/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: wave-interference/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/wave-interference/package.json b/wave-interference/package.json
--- a/wave-interference/package.json	(revision 913f8e10d6860a37cce8de184b3fab0efd6b9ee9)
+++ b/wave-interference/package.json	(date 1710537720375)
@@ -50,6 +50,11 @@
         "rules": {
           "bad-typescript-text": "off",
           "@typescript-eslint/explicit-module-boundary-types": "off"
+        },
+        "parserOptions": {
+          "project": [
+            "../wave-interference/tsconfig.json"
+          ]
         }
       }
     ]
Index: wave-on-a-string/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/wave-on-a-string/package.json b/wave-on-a-string/package.json
--- a/wave-on-a-string/package.json	(revision 120d1dc6b9666b2ac1024683e70f9b2510d95677)
+++ b/wave-on-a-string/package.json	(date 1710537720406)
@@ -22,6 +22,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../wave-on-a-string/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: waves-intro/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/waves-intro/package.json b/waves-intro/package.json
--- a/waves-intro/package.json	(revision b37390ca5109dfc052b452c2f881a6df5a947529)
+++ b/waves-intro/package.json	(date 1710537720436)
@@ -36,6 +36,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../waves-intro/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: weddell/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/weddell/package.json b/weddell/package.json
--- a/weddell/package.json	(revision e28ec3dcd6a2e7f06c690588b34d0de7baf69390)
+++ b/weddell/package.json	(date 1710537720466)
@@ -103,6 +103,18 @@
       "/assets/**",
       "/project/**",
       "/resources/**"
-    ]
-  }
-}
+    ],
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../weddell/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: wilder/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/wilder/package.json b/wilder/package.json
--- a/wilder/package.json	(revision b38f5fa4b6f1b94fb553562b008bd45d4a4bd6c6)
+++ b/wilder/package.json	(date 1710537720497)
@@ -21,6 +21,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../wilder/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: xray-diffraction/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/xray-diffraction/package.json b/xray-diffraction/package.json
--- a/xray-diffraction/package.json	(revision b844a36ceb5464b29bf3a9f11cf0d6ec7403626a)
+++ b/xray-diffraction/package.json	(date 1710537720527)
@@ -20,6 +20,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../xray-diffraction/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: acid-base-solutions/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/acid-base-solutions/package.json b/acid-base-solutions/package.json
--- a/acid-base-solutions/package.json	(revision 7068245060a41dde47325911ce9e189185df608c)
+++ b/acid-base-solutions/package.json	(date 1710537714386)
@@ -53,6 +53,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../acid-base-solutions/tsconfig.json"
+          ]
         }
       }
     ]
Index: alpenglow/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/alpenglow/package.json b/alpenglow/package.json
--- a/alpenglow/package.json	(revision 1977872f17e6b07e6c4514e39185cce66632dbef)
+++ b/alpenglow/package.json	(date 1710537714423)
@@ -32,6 +32,18 @@
     "rules": {
       "no-bitwise": "off",
       "todo-should-have-issue": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../alpenglow/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: aqua/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/aqua/package.json b/aqua/package.json
--- a/aqua/package.json	(revision 0071d66a72fb71456b91e6d97601f87be1273894)
+++ b/aqua/package.json	(date 1710537714454)
@@ -29,7 +29,19 @@
       "kite": "readonly",
       "scenery": "readonly",
       "__dirname": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../aqua/tsconfig.json"
+          ]
+        }
+      }
+    ]
   },
   "phet": {
     "buildStandalone": true,
Index: area-builder/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-builder/package.json b/area-builder/package.json
--- a/area-builder/package.json	(revision d731703e04dc33f8aee74395c521ac331f593a60)
+++ b/area-builder/package.json	(date 1710537714486)
@@ -32,6 +32,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-builder/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: area-model-algebra/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-model-algebra/package.json b/area-model-algebra/package.json
--- a/area-model-algebra/package.json	(revision a397ef2d1da48715ce1fb559b77548174a2b68a5)
+++ b/area-model-algebra/package.json	(date 1710537714517)
@@ -43,6 +43,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-model-algebra/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: area-model-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-model-common/package.json b/area-model-common/package.json
--- a/area-model-common/package.json	(revision f4f5a435151c9c1c751582cf658e1b48d28dafcb)
+++ b/area-model-common/package.json	(date 1710537714547)
@@ -19,6 +19,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-model-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: area-model-decimals/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-model-decimals/package.json b/area-model-decimals/package.json
--- a/area-model-decimals/package.json	(revision 7914ec0930ac4e7f189ac63c5de54d435481bad6)
+++ b/area-model-decimals/package.json	(date 1710537714578)
@@ -26,6 +26,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-model-decimals/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: area-model-introduction/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-model-introduction/package.json b/area-model-introduction/package.json
--- a/area-model-introduction/package.json	(revision d8fd98c2051cf807e51bbf26ccab6e2dbeec433a)
+++ b/area-model-introduction/package.json	(date 1710537714608)
@@ -30,6 +30,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-model-introduction/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: area-model-multiplication/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/area-model-multiplication/package.json b/area-model-multiplication/package.json
--- a/area-model-multiplication/package.json	(revision 8c61a07dba153c9068d086273e37d5d5a98d19c6)
+++ b/area-model-multiplication/package.json	(date 1710537714639)
@@ -42,6 +42,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../area-model-multiplication/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: arithmetic/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/arithmetic/package.json b/arithmetic/package.json
--- a/arithmetic/package.json	(revision 82967d294b707b4e027f3bc4f72f58fcb624d95f)
+++ b/arithmetic/package.json	(date 1710537714670)
@@ -51,6 +51,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../arithmetic/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: assert/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/assert/package.json b/assert/package.json
--- a/assert/package.json	(revision dd61947e1ba2c0655a242bebad9b887b397b01dd)
+++ b/assert/package.json	(date 1710537714700)
@@ -10,6 +10,18 @@
     "grunt": "~1.5.3"
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../assert/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: atomic-interactions/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/atomic-interactions/package.json b/atomic-interactions/package.json
--- a/atomic-interactions/package.json	(revision 3668822c684fd1c72a34e63f21ef2d54cdf52f2e)
+++ b/atomic-interactions/package.json	(date 1710537714732)
@@ -31,6 +31,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../atomic-interactions/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: axon/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/axon/package.json b/axon/package.json
--- a/axon/package.json	(revision 67b547e8ac87f09ad7c0ab035948de0122ad3c10)
+++ b/axon/package.json	(date 1710537714762)
@@ -19,6 +19,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../axon/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: balancing-act/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/balancing-act/package.json b/balancing-act/package.json
--- a/balancing-act/package.json	(revision 0c41ad0641e47d036ade0a11389be7d6aff4af7d)
+++ b/balancing-act/package.json	(date 1710537714822)
@@ -46,6 +46,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../balancing-act/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: balancing-chemical-equations/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/balancing-chemical-equations/package.json b/balancing-chemical-equations/package.json
--- a/balancing-chemical-equations/package.json	(revision d1b176b2cb434650253a31b106822dc40e9c3432)
+++ b/balancing-chemical-equations/package.json	(date 1710537714852)
@@ -52,6 +52,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../balancing-chemical-equations/tsconfig.json"
+          ]
         }
       }
     ]
Index: balloons-and-static-electricity/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/balloons-and-static-electricity/package.json b/balloons-and-static-electricity/package.json
--- a/balloons-and-static-electricity/package.json	(revision 8a0bbf3f945cf31f69dd7b07b7668de9ac83211f)
+++ b/balloons-and-static-electricity/package.json	(date 1710537714883)
@@ -37,6 +37,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../balloons-and-static-electricity/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: bamboo/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/bamboo/package.json b/bamboo/package.json
--- a/bamboo/package.json	(revision 522e43d9e359f201f24e23d5a6c2f2bf1f2507af)
+++ b/bamboo/package.json	(date 1710537714914)
@@ -25,6 +25,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/phet-library_eslintrc.js"
+    "extends": "../chipper/eslint/phet-library_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../bamboo/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: beers-law-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/beers-law-lab/package.json b/beers-law-lab/package.json
--- a/beers-law-lab/package.json	(revision d1e56f7fb94d8bb81d339bd90c08e950bdaba3a9)
+++ b/beers-law-lab/package.json	(date 1710537714944)
@@ -57,6 +57,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../beers-law-lab/tsconfig.json"
+          ]
         }
       }
     ]
Index: bending-light/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/bending-light/package.json b/bending-light/package.json
--- a/bending-light/package.json	(revision 85f35315f2fb92b06404015122076a41e5c9852d)
+++ b/bending-light/package.json	(date 1710537714977)
@@ -30,6 +30,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../bending-light/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: binder/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/binder/package.json b/binder/package.json
--- a/binder/package.json	(revision 28a643856ef52dca89d4511f7a6fb6aae90c906f)
+++ b/binder/package.json	(date 1710537715009)
@@ -36,6 +36,18 @@
       "react": {
         "version": "~16.8.6"
       }
-    }
-  }
-}
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../binder/tsconfig.json"
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
Index: blackbody-spectrum/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/blackbody-spectrum/package.json b/blackbody-spectrum/package.json
--- a/blackbody-spectrum/package.json	(revision 08f9739e741713434f7e19dbb36f29a056f4d9b6)
+++ b/blackbody-spectrum/package.json	(date 1710537715040)
@@ -28,6 +28,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../blackbody-spectrum/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: blast/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/blast/package.json b/blast/package.json
--- a/blast/package.json	(revision f7180ac713a8cc27d7dd7b7154d8e4b7e14806a9)
+++ b/blast/package.json	(date 1710537715071)
@@ -25,6 +25,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../blast/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: brand/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/brand/package.json b/brand/package.json
--- a/brand/package.json	(revision 5e614c8d6309de200bd9166991cf395c16865cfe)
+++ b/brand/package.json	(date 1710537715103)
@@ -14,6 +14,18 @@
     "supportsOutputJS": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../brand/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: build-a-fraction/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/build-a-fraction/package.json b/build-a-fraction/package.json
--- a/build-a-fraction/package.json	(revision 46d0f1733801003351a7a066c06d506c2fc16278)
+++ b/build-a-fraction/package.json	(date 1710537715133)
@@ -34,6 +34,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../build-a-fraction/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: build-a-molecule/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/build-a-molecule/package.json b/build-a-molecule/package.json
--- a/build-a-molecule/package.json	(revision 63455ed3d9da72281422d3a6c9d684b7c8c03ef9)
+++ b/build-a-molecule/package.json	(date 1710537715164)
@@ -43,6 +43,18 @@
     },
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../build-a-molecule/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: magnets-and-electromagnets/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/magnets-and-electromagnets/package.json b/magnets-and-electromagnets/package.json
--- a/magnets-and-electromagnets/package.json	(revision 312119c018522034c12d252f5d3cb992cae96ef1)
+++ b/magnets-and-electromagnets/package.json	(date 1710537717610)
@@ -54,6 +54,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../magnets-and-electromagnets/tsconfig.json"
+          ]
         }
       }
     ]
Index: build-a-nucleus/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/build-a-nucleus/package.json b/build-a-nucleus/package.json
--- a/build-a-nucleus/package.json	(revision 5ec462c44b97fe0d673a951922e000478ca323ed)
+++ b/build-a-nucleus/package.json	(date 1710537715195)
@@ -35,6 +35,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../build-a-nucleus/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: build-an-atom/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/build-an-atom/package.json b/build-an-atom/package.json
--- a/build-an-atom/package.json	(revision 4347e64b3e17820414f5424e5359bcb4fcc31193)
+++ b/build-an-atom/package.json	(date 1710537715225)
@@ -37,6 +37,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../build-an-atom/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: bumper/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/bumper/package.json b/bumper/package.json
--- a/bumper/package.json	(revision 1563bda52ac1bef95b2cd28edce05e640c3c9a16)
+++ b/bumper/package.json	(date 1710537715256)
@@ -26,6 +26,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../bumper/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: buoyancy/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/buoyancy/package.json b/buoyancy/package.json
--- a/buoyancy/package.json	(revision fa89a7072b089530be5b33c0af12ba1aced7445f)
+++ b/buoyancy/package.json	(date 1710537715286)
@@ -49,6 +49,18 @@
       "p2": "readonly",
       "THREE": "readonly",
       "decomp": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../buoyancy/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: calculus-grapher/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/calculus-grapher/package.json b/calculus-grapher/package.json
--- a/calculus-grapher/package.json	(revision 10c3dd129d32c5b6b6428c0426d9d738231e474b)
+++ b/calculus-grapher/package.json	(date 1710537715348)
@@ -56,6 +56,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../calculus-grapher/tsconfig.json"
+          ]
         }
       }
     ]
Index: capacitor-lab-basics/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/capacitor-lab-basics/package.json b/capacitor-lab-basics/package.json
--- a/capacitor-lab-basics/package.json	(revision f765d01d50160235a6d8a077a419c0dc80920ddc)
+++ b/capacitor-lab-basics/package.json	(date 1710537715378)
@@ -40,6 +40,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../capacitor-lab-basics/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: center-and-variability/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/center-and-variability/package.json b/center-and-variability/package.json
--- a/center-and-variability/package.json	(revision de37aec3d5eee0422cb6f7700f9653ab70c750c1)
+++ b/center-and-variability/package.json	(date 1710537715409)
@@ -71,6 +71,11 @@
               ]
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../center-and-variability/tsconfig.json"
+          ]
         }
       }
     ]
Index: chains/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chains/package.json b/chains/package.json
--- a/chains/package.json	(revision 31b760d08621dd41ddc02c1c65a99fa71605fcef)
+++ b/chains/package.json	(date 1710537715440)
@@ -27,6 +27,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../chains/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: charges-and-fields/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/charges-and-fields/package.json b/charges-and-fields/package.json
--- a/charges-and-fields/package.json	(revision 742eca2328e3742001ccdfd8e00c53f23d7380d4)
+++ b/charges-and-fields/package.json	(date 1710537715471)
@@ -31,6 +31,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../charges-and-fields/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: brand/tsconfig.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/brand/tsconfig.json b/brand/tsconfig.json
--- a/brand/tsconfig.json	(revision 5e614c8d6309de200bd9166991cf395c16865cfe)
+++ b/brand/tsconfig.json	(date 1710540587993)
@@ -4,6 +4,18 @@
     "js/**/*",
     "images/**/*",
     "mipmaps/**/*",
-    "sounds/**/*"
+    "sounds/**/*",
+
+    "adapted-from-phet/images/**/*",
+    "adapted-from-phet/js/**/*",
+
+    "phet/images/**/*",
+    "phet/js/**/*",
+
+    "phet-io/images/**/*",
+    "phet-io/js/**/*",
+
+    "adapted-from-phet/images/**/*",
+    "adapted-from-phet/js/**/*",
   ]
 }
\ No newline at end of file
Index: chipper/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/package.json b/chipper/package.json
--- a/chipper/package.json	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/package.json	(date 1710555475915)
@@ -27,16 +27,16 @@
     "@types/three": "~0.137.0",
     "@types/react": "~18.0.12",
     "@types/react-dom": "~18.0.5",
-    "@typescript-eslint/parser": "~6.18.1",
-    "@typescript-eslint/eslint-plugin": "~6.18.1",
-    "@typescript-eslint/utils": "~6.18.1",
-    "eslint-plugin-html": "~7.1.0",
+    "@typescript-eslint/parser": "~7.2.0",
+    "@typescript-eslint/eslint-plugin": "~7.2.0",
+    "@typescript-eslint/utils": "~7.2.0",
+    "eslint-plugin-html": "~8.0.0",
     "@webgpu/types": "~0.1.34",
     "archiver": "~5.3.0",
     "axios": "~0.21.4",
     "@babel/eslint-parser": "~7.19.1",
     "docdash": "~1.2.0",
-    "eslint": "~8.28.0",
+    "eslint": "~8.57.0",
     "eslint-plugin-react": "~7.31.11",
     "expose-loader": "~4.1.0",
     "grunt": "~1.5.3",
@@ -82,8 +82,13 @@
           "**/*.ts",
           "**/*.tsx"
         ],
-        "parser": "@typescript-eslint/parser"
+        "parser": "@typescript-eslint/parser",
+        "parserOptions": {
+          "project": [
+            "../chipper/tsconfig.json"
+          ]
+        }
       }
     ]
   }
-}
+}
\ No newline at end of file
Index: circuit-construction-kit-ac-virtual-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-ac-virtual-lab/package.json b/circuit-construction-kit-ac-virtual-lab/package.json
--- a/circuit-construction-kit-ac-virtual-lab/package.json	(revision 2a681d58c9f215cd6158500f3960760236c173d8)
+++ b/circuit-construction-kit-ac-virtual-lab/package.json	(date 1710537715563)
@@ -33,6 +33,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-ac-virtual-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: circuit-construction-kit-ac/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-ac/package.json b/circuit-construction-kit-ac/package.json
--- a/circuit-construction-kit-ac/package.json	(revision 99913a6eb39b1450d27b553095ce96c4245519c9)
+++ b/circuit-construction-kit-ac/package.json	(date 1710537715532)
@@ -38,6 +38,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-ac/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: circuit-construction-kit-black-box-study/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-black-box-study/package.json b/circuit-construction-kit-black-box-study/package.json
--- a/circuit-construction-kit-black-box-study/package.json	(revision 007c52c5edab203db9033864301330abc0e34fb4)
+++ b/circuit-construction-kit-black-box-study/package.json	(date 1710537715594)
@@ -32,6 +32,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-black-box-study/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: circuit-construction-kit-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-common/package.json b/circuit-construction-kit-common/package.json
--- a/circuit-construction-kit-common/package.json	(revision c76b4fb5936db20b6e106720da00ffb415a27f1e)
+++ b/circuit-construction-kit-common/package.json	(date 1710537715625)
@@ -26,6 +26,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: circuit-construction-kit-dc-virtual-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-dc-virtual-lab/package.json b/circuit-construction-kit-dc-virtual-lab/package.json
--- a/circuit-construction-kit-dc-virtual-lab/package.json	(revision a27ebe958058d8cfc45f47ac165f3d941ef11404)
+++ b/circuit-construction-kit-dc-virtual-lab/package.json	(date 1710537715686)
@@ -38,6 +38,18 @@
     }
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-dc-virtual-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: circuit-construction-kit-dc/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/circuit-construction-kit-dc/package.json b/circuit-construction-kit-dc/package.json
--- a/circuit-construction-kit-dc/package.json	(revision f01216d875ed656b26001e25d1d83654f830a032)
+++ b/circuit-construction-kit-dc/package.json	(date 1710537715656)
@@ -44,6 +44,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../circuit-construction-kit-dc/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: collision-lab/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/collision-lab/package.json b/collision-lab/package.json
--- a/collision-lab/package.json	(revision 5443e0bf285c18938c8335fa0b5b1d50def4b076)
+++ b/collision-lab/package.json	(date 1710537715717)
@@ -33,6 +33,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "globals": {
       "sceneryLog": "readonly"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../collision-lab/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: color-vision/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/color-vision/package.json b/color-vision/package.json
--- a/color-vision/package.json	(revision f88a721be8ad82391d8bffdf00af52782ff0e7f8)
+++ b/color-vision/package.json	(date 1710537715748)
@@ -30,6 +30,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../color-vision/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: concentration/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/concentration/package.json b/concentration/package.json
--- a/concentration/package.json	(revision ad677b3b6d706f2d87cc229bbc5cb8ade5971ca5)
+++ b/concentration/package.json	(date 1710537715809)
@@ -51,6 +51,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../concentration/tsconfig.json"
+          ]
         }
       }
     ]
Index: coulombs-law/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/coulombs-law/package.json b/coulombs-law/package.json
--- a/coulombs-law/package.json	(revision d3dffc755412f8712ce1115e23ed212af32337a5)
+++ b/coulombs-law/package.json	(date 1710537715840)
@@ -36,6 +36,18 @@
     ]
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../coulombs-law/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: counting-common/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/counting-common/package.json b/counting-common/package.json
--- a/counting-common/package.json	(revision 8eabf89f68c44bda16a55c8a639472ead473a32c)
+++ b/counting-common/package.json	(date 1710537715870)
@@ -17,6 +17,18 @@
     "extends": "../chipper/eslint/sim_eslintrc.js",
     "rules": {
       "no-view-imported-from-model": "off"
-    }
+    },
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../counting-common/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: curve-fitting/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/curve-fitting/package.json b/curve-fitting/package.json
--- a/curve-fitting/package.json	(revision ff80b1027f545e5b1dda6b62c0f9b02b7491613d)
+++ b/curve-fitting/package.json	(date 1710537715901)
@@ -28,6 +28,18 @@
     "published": true
   },
   "eslintConfig": {
-    "extends": "../chipper/eslint/sim_eslintrc.js"
+    "extends": "../chipper/eslint/sim_eslintrc.js",
+    "overrides": [
+      {
+        "files": [
+          "**/*.ts"
+        ],
+        "parserOptions": {
+          "project": [
+            "../curve-fitting/tsconfig.json"
+          ]
+        }
+      }
+    ]
   }
 }
\ No newline at end of file
Index: chipper/js/grunt/lint.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/chipper/js/grunt/lint.js b/chipper/js/grunt/lint.js
--- a/chipper/js/grunt/lint.js	(revision 49365d759571523891e8143e8aa5811c93dbd3db)
+++ b/chipper/js/grunt/lint.js	(date 1710876392693)
@@ -18,6 +18,10 @@
 const CacheLayer = require( '../common/CacheLayer' );
 const crypto = require( 'crypto' );
 
+// const exported = require( '../../../chipper/node_modules/@typescript-eslint/typescript-estree/dist/index.js' );
+// const clearCaches = clearCachesExport.clearCaches;
+// debugger;
+
 // constants
 const EXCLUDE_REPOS = [ 'binder', 'fenster', 'decaf', 'scenery-lab-demo' ];
 
@@ -25,6 +29,8 @@
 // out of the repo running the command
 const repoToPattern = repo => `../${repo}`;
 
+process.env.TSESTREE_SINGLE_RUN = 'true'
+
 async function consoleLogResults( results ) {
 
   // No need to have the same ESLint just to format
@@ -48,9 +54,15 @@
     inProgressErrorLogging: false // print out the
   }, options );
 
-  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known memory leak.  May
-  // need to clear the cache directory in a few years?
-  const tsconfigFile = fs.readFileSync( '../chipper/tsconfig/all/tsconfig.json', 'utf-8' );
+  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known file system leak, because
+  // the old cache directory is not cleared when a new one is formed.  May need to clear the cache directory manually in a few years?
+  let tsconfigFile = '';
+  try {
+    tsconfigFile = fs.readFileSync( `../${repo}/tsconfig.json`, 'utf-8' );
+  }
+  catch( e ) {
+    // tsconfig file not found
+  }
 
   // Also cache on package.json so that when eslint plugins change, it will invalidate the caches. Note this will
   // have false positives because it is possible to change package.json without changing
Index: magnet-and-compass/package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/magnet-and-compass/package.json b/magnet-and-compass/package.json
--- a/magnet-and-compass/package.json	(revision 6258461f15167df362d5bacb47a383560a560da7)
+++ b/magnet-and-compass/package.json	(date 1710537717579)
@@ -49,6 +49,11 @@
               "ts-nocheck": true
             }
           ]
+        },
+        "parserOptions": {
+          "project": [
+            "../magnet-and-compass/tsconfig.json"
+          ]
         }
       }
     ]

@samreid
Copy link
Member

samreid commented Mar 19, 2024

In the last few days, CT started failing lint-everything in every column due to this out of memory error:

perennial : lint-everything
Lint-everything failed with status code null:
Running "lint-everything" task

<--- Last few GCs --->

[1502318:0x6def2e0] 687205 ms: Scavenge 3903.2 (4125.5) -> 3892.7 (4127.3) MB, 30.7 / 0.0 ms (average mu = 0.317, current mu = 0.307) allocation failure;
[1502318:0x6def2e0] 687338 ms: Scavenge 3907.8 (4127.3) -> 3898.1 (4127.8) MB, 37.0 / 0.0 ms (average mu = 0.317, current mu = 0.307) allocation failure;
[1502318:0x6def2e0] 687454 ms: Scavenge 3911.7 (4127.9) -> 3902.7 (4128.7) MB, 26.2 / 0.0 ms (average mu = 0.317, current mu = 0.307) allocation failure;

<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 0xb7a940 node::Abort() [grunt]
2: 0xa8e823 [grunt]
3: 0xd5c940 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [grunt]
4: 0xd5cce7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [grunt]
5: 0xf3a3e5 [grunt]
6: 0xf3b2e8 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [grunt]
7: 0xf4b7f3 [grunt]
8: 0xf4c668 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [grunt]
9: 0xf26fce v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [grunt]
10: 0xf28397 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [grunt]
11: 0xf0956a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [grunt]
12: 0x12ce7af v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [grunt]
13: 0x16fb6b9 [grunt]
Snapshot from 3/19/2024, 3:04:21 PM

@samreid
Copy link
Member

samreid commented Mar 20, 2024

@zepumph and I wrote this worker thread implementation:

// Copyright 2022-2023, University of Colorado Boulder

/**
 * Runs the lint rules on the specified files.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */


// modules
const _ = require( 'lodash' );
const { ESLint } = require( 'eslint' ); // eslint-disable-line require-statement-match
const fs = require( 'fs' );
const chipAway = require( './chipAway' );
const disableWithComment = require( './disableWithComment' );
const showCommandLineProgress = require( '../common/showCommandLineProgress' );
const CacheLayer = require( '../common/CacheLayer' );
const crypto = require( 'crypto' );
const { Worker } = require( 'worker_threads' );

// constants
const EXCLUDE_REPOS = [ 'binder', 'fenster', 'decaf', 'scenery-lab-demo' ];

// "Pattern" is really a path, we assume here that gruntfiles help keep the right directory structure and can just pop
// out of the repo running the command
const repoToPattern = repo => `../${repo}`;

async function consoleLogResults( results ) {

  // No need to have the same ESLint just to format
  const formatter = await new ESLint().loadFormatter( 'stylish' );
  const resultText = formatter.format( results );
  console.log( `\n${resultText}\n` );
}

/**
 * Create an ESLint client and lint a single repo
 * @param {string} repo
 * @param {Object} [options]
 * @returns {Promise<Object>} - results from linting files, see ESLint.lintFiles
 */
const lintOneRepo = async ( repo, options ) => {

  options = _.assignIn( {
    cache: true,
    fix: false,
    format: false,
    inProgressErrorLogging: false // print out the
  }, options );

  // Hash on tsconfig file so when tsconfig changes it invalidates the cache.  NOTE this is a known memory leak.  May
  // need to clear the cache directory in a few years?
  const tsconfigFile = fs.readFileSync( '../chipper/tsconfig/all/tsconfig.json', 'utf-8' );

  // Also cache on package.json so that when eslint plugins change, it will invalidate the caches. Note this will
  // have false positives because it is possible to change package.json without changing
  // the eslint plugins
  const packageJSON = fs.readFileSync( '../chipper/package.json', 'utf-8' );

  const hash = crypto.createHash( 'md5' ).update( tsconfigFile + packageJSON ).digest( 'hex' );

  const eslintConfig = {

    // optional auto-fix
    fix: options.fix,

    // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
    // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
    // the process was run from. If false, this will delete the `cacheLocation` file.
    cache: options.cache,

    // Where to store the target-specific cache file.  Use only first 4 digits of hash to improve readability
    // at the risk of having more key collisions
    cacheLocation: `../chipper/eslint/cache/${repo}-${hash.substring( 0, 8 )}.eslintcache`,

    ignorePath: '../chipper/eslint/.eslintignore',

    resolvePluginsRelativeTo: '../chipper/',

    // Our custom rules live here
    rulePaths: [ '../chipper/eslint/rules' ],

    extensions: [ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.html' ],

    // If no lintable files are found, it is not an error
    errorOnUnmatchedPattern: false
  };

  const cacheKey = `lintRepo#${repo}`;

  if ( options.cache && CacheLayer.isCacheSafe( cacheKey ) ) {
    // console.log( 'lint cache hit: ' + cacheKey );
    return [];
  }
  else {
    // console.log( 'lint cache fail: ' + cacheKey );
  }

  const config = {};
  const configExtends = [];
  if ( options.format ) {
    configExtends.push( '../chipper/eslint/format_eslintrc.js' );
  }

  config.extends = configExtends;
  eslintConfig.baseConfig = config;

  const eslint = new ESLint( eslintConfig );

  const results = await eslint.lintFiles( repoToPattern( repo ) );

  const totalWarnings = _.sum( results.map( result => result.warningCount ) );
  const totalErrors = _.sum( results.map( result => result.errorCount ) );
  if ( options.cache && totalWarnings === 0 && totalErrors === 0 ) {
    CacheLayer.onSuccess( cacheKey );
  }

  if ( options.inProgressErrorLogging && totalWarnings + totalErrors > 0 ) {
    console.log( `\n\n${repo}:` );
    await consoleLogResults( results );
  }

  return results;
};

/**
 * Lints the specified repositories.
 * @public
 *
 * @param {string[]} repos - list of repos to lint
 * @param {Object} [options]
 * @returns {Promise<{results:Object,ok:boolean}>} - results from linting files, see ESLint.lintFiles (all results, not just errors).
 */
const lint = async ( repos, options ) => {

  // Run all linting from chipper so the ESLint cache will be shared, see https://github.com/phetsims/chipper/issues/1286
  const cwd = process.cwd();
  process.chdir( '../chipper' );

  options = _.merge( {
    cache: true,
    format: false, // append an extra set of rules for formatting code.
    fix: false, // whether fixes should be written to disk
    chipAway: false, // returns responsible dev info for easier chipping.
    disableWithComment: false, // replaces failing typescript lines with eslint disable and related comment
    showProgressBar: true
  }, options );

  // filter out all unlintable repos. An unlintable repo is one that has no `js` in it, so it will fail when trying to
  // lint it.  Also, if the user doesn't have some repos checked out, those should be skipped
  repos = repos.filter( repo => !EXCLUDE_REPOS.includes( repo ) &&
                                fs.existsSync( repoToPattern( repo ) ) );

  const inProgressErrorLogging = repos.length > 1;

  const allResults = [];
  for ( let i = 0; i < repos.length; i++ ) {
    options.showProgressBar && repos.length > 1 && showCommandLineProgress( i / repos.length, false );

    try {

      const myPromise = new Promise( ( resolve, reject ) => {
        const worker = new Worker( __dirname + '/lintMain.js' );
        worker.on( 'message', resolve );
        worker.on( 'error', reject );
        worker.on( 'exit', code => {
          if ( code !== 0 ) {
            reject( new Error( `Worker stopped with exit code ${code}` ) );
          }
        } );

        worker.postMessage( {
          repo: repos[ i ],
          options: {
            cache: options.cache,
            format: options.format,
            fix: options.fix,
            inProgressErrorLogging: inProgressErrorLogging
          }
        } );
      } );

      const result = await myPromise;

      allResults.push( ...result );
    }
    catch( e ) {
      console.error( e ); // make sure that the error ends up on stderr
      throw e;
    }
  }

  options.showProgressBar && repos.length > 1 && showCommandLineProgress( 1, true );

  // Modify the files with the fixed code.
  if ( options.fix ) {
    await ESLint.outputFixes( allResults );
  }

  // Parse the results.
  const totalWarnings = _.sum( allResults.map( result => result.warningCount ) );
  const totalErrors = _.sum( allResults.map( result => result.errorCount ) );

  // Output results on errors.
  if ( totalWarnings + totalErrors > 0 ) {

    // This exact string is used in AQUA/QuickServer to parse messaging for slack reporting
    const IMPORTANT_MESSAGE_DO_NOT_EDIT = 'All results (repeated from above)';
    inProgressErrorLogging && console.log( `\n\n${IMPORTANT_MESSAGE_DO_NOT_EDIT}\n` );

    await consoleLogResults( allResults );

    // The chip-away option provides a quick and easy method to assign devs to their respective repositories.
    // Check ./chipAway.js for more information.
    if ( options.chipAway ) {
      const message = chipAway( allResults );
      console.log( 'Results from chipAway: \n' + message );
    }

    if ( options.disableWithComment ) {
      disableWithComment( allResults );
    }
  }

  process.chdir( cwd );

  const ok = totalWarnings + totalErrors === 0;

  return {
    results: allResults,
    ok: ok
  };
};

// Mark the version so that the pre-commit hook will only try to use the promise-based API, this means
// it won't run lint precommit hook on SHAs before the promise-based API
lint.chipperAPIVersion = 'promisesPerRepo1';

lint.lintOneRepo = lintOneRepo;

module.exports = lint;

@samreid
Copy link
Member

samreid commented Mar 20, 2024

lintMain.js

const lint = require( './lint' );
const { parentPort } = require( 'worker_threads' );

parentPort.on( 'message', async ( { repo, options } ) => {
  const result = await lint.lintOneRepo( repo, options );
  parentPort.postMessage( result );

  process.exit( 0 );
} );

@zepumph zepumph changed the title all/tsconfig.json should be smarter about entry points Lint takes too long and has a memory leak Mar 20, 2024
@zepumph zepumph removed their assignment Mar 22, 2024
@samreid samreid removed their assignment Apr 1, 2024
@zepumph
Copy link
Member Author

zepumph commented Apr 2, 2024

As we continue to run into this memory error, both in lint and tsc-all, we should note that you can get around the issue with a node option:

https://stackoverflow.com/questions/48387040/how-do-i-determine-the-correct-max-old-space-size-for-node-js

--max-old-space-size=8192 is a good place to start. It can be added as a CLI option to node, or put in the bashrc like:
export NODE_OPTIONS=--max_old_space_size=8192

@zepumph
Copy link
Member Author

zepumph commented Apr 9, 2024

Let's also put this on hold until #1431 is complete. (in addition to #1429).

@zepumph
Copy link
Member Author

zepumph commented Aug 15, 2024

Taking off hold because the above issues are completed. Now that #1424 is complete. I would like to take another look at this, to see if we have to use the tsconfig all for eslint. This is also similar to #1356 where we want to try to speed up type checking generally, perhaps with project references.

@samreid samreid self-assigned this Sep 20, 2024
@samreid
Copy link
Member

samreid commented Sep 20, 2024

By ramping up the memory and seeing when a crash occurs, we can see how long our heap limit may be safe. I tested with time grunt lint-everything --disable-eslint-cache and iteratively turning up the heap size.

image

I saw that with a heap size of --max-old-space-size=4000 we get through around 200 repos, so the proposed value of 8196 seems safe for a long time.

@samreid
Copy link
Member

samreid commented Sep 26, 2024

Note that the operational characteristics are very different after #1451. We have a hybrid approach (node API + processes) that is probably not ideal. Let's discuss with @zepumph how to proceed.

@zepumph
Copy link
Member Author

zepumph commented Oct 10, 2024

our chipper lint task is still clunky and memory-heavy. We should wait to see how #1451 completes before spending more effort on this.

Ideas:

  1. Determining how many repo entrypoints we can include in a single process (whether npx or the node client).
  2. Using Node's memory analytics to detect when the memory footprint is too large, and a new process is needed.

@zepumph
Copy link
Member Author

zepumph commented Oct 11, 2024

Let's pick most of this up in #1484.

@samreid samreid removed their assignment Oct 14, 2024
samreid pushed a commit to phetsims/perennial that referenced this issue Oct 17, 2024
samreid added a commit to phetsims/perennial that referenced this issue Oct 17, 2024
samreid pushed a commit to phetsims/perennial that referenced this issue Oct 17, 2024
samreid pushed a commit to phetsims/perennial that referenced this issue Oct 17, 2024
samreid pushed a commit to phetsims/perennial that referenced this issue Oct 17, 2024
zepumph pushed a commit to phetsims/perennial that referenced this issue Oct 22, 2024
@zepumph
Copy link
Member Author

zepumph commented Nov 5, 2024

Linting is much faster and better over in #1484, and with no memory crash! Let's pick things up in that issue.

@zepumph zepumph closed this as completed Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants