initial parser
This commit is contained in:
commit
d0d6aae1e5
175
.gitignore
vendored
Normal file
175
.gitignore
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
18
.prettierrc
Normal file
18
.prettierrc
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": true,
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"jsxBracketSameLine": false,
|
||||
"jsxSingleQuote": true,
|
||||
"printWidth": 80,
|
||||
"proseWrap": "always",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false,
|
||||
"plugins": ["prettier-plugin-pegjs"]
|
||||
}
|
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
||||
An interpreter for the CPS intermediate representation as
|
||||
suggested in "Compiling with Continuations" by Appel.
|
18
package.json
Normal file
18
package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "cps-interpreter",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.8",
|
||||
"peggy": "^4.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-pegjs": "^2.0.2",
|
||||
"ts-pegjs": "^4.2.1"
|
||||
}
|
||||
}
|
11
src/args.ts
Normal file
11
src/args.ts
Normal file
@ -0,0 +1,11 @@
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
|
||||
export type Args = {
|
||||
devMode: boolean;
|
||||
repl: boolean;
|
||||
};
|
||||
|
||||
export const args: Args = {
|
||||
repl: argv.repl ?? false,
|
||||
devMode: argv.dev ?? false,
|
||||
};
|
63
src/index.ts
Normal file
63
src/index.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { args, type Args } from '@/args';
|
||||
import { join } from 'path';
|
||||
import { watch } from 'fs/promises';
|
||||
import { generateParser, GRAMMAR_FILE, GENERATED_PARSER } from '@/parser';
|
||||
import {
|
||||
ConsoleTracingLogger,
|
||||
type LogLevel,
|
||||
type TracingLogger,
|
||||
} from '@/utils';
|
||||
import { evaluate } from '@/interpreter';
|
||||
|
||||
const LOG_LEVELS: LogLevel[] = ['info', 'warn', 'error'];
|
||||
|
||||
const devMode = async (logger: TracingLogger) => {
|
||||
logger.info('Watching for changes in parser...');
|
||||
|
||||
const watcher = watch(import.meta.dir, { recursive: true });
|
||||
for await (const event of watcher) {
|
||||
if (event.filename?.endsWith(GRAMMAR_FILE)) {
|
||||
const grammarFile = join(import.meta.dir, event.filename);
|
||||
const outputFile = join(
|
||||
import.meta.dir,
|
||||
event.filename.replace(GRAMMAR_FILE, GENERATED_PARSER),
|
||||
);
|
||||
logger.info(
|
||||
`Generating parser at Location=(${grammarFile}) to Source=(${outputFile})...`,
|
||||
);
|
||||
generateParser(grammarFile, outputFile);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const doRepl = async (prompt = '~> ') => {
|
||||
process.stdout.write(prompt);
|
||||
|
||||
for await (const line of console) {
|
||||
const result = await evaluate(line);
|
||||
console.log(result);
|
||||
break;
|
||||
}
|
||||
|
||||
await doRepl(prompt);
|
||||
};
|
||||
|
||||
export const main = async (args: Args) => {
|
||||
if (args.devMode) {
|
||||
LOG_LEVELS.push('debug');
|
||||
}
|
||||
|
||||
const logger = new ConsoleTracingLogger('main', LOG_LEVELS);
|
||||
|
||||
if (args.devMode) {
|
||||
logger.info('Starting in dev mode...');
|
||||
await devMode(logger);
|
||||
}
|
||||
|
||||
if (args.repl) {
|
||||
logger.info('Starting REPL...');
|
||||
logger.info('Welcome to the CPS interpreter!');
|
||||
}
|
||||
};
|
||||
|
||||
main(args);
|
1
src/interpreter/index.ts
Normal file
1
src/interpreter/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export const evaluate = async (ast: Program) => {};
|
17
src/parser/generate.ts
Normal file
17
src/parser/generate.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import peggy from 'peggy';
|
||||
const tspegjs: any = require('ts-pegjs');
|
||||
|
||||
export const GRAMMAR_FILE = 'grammar.pegjs';
|
||||
export const GENERATED_PARSER = 'parser.ts';
|
||||
|
||||
export const generateParser = async (file: string, output: string) => {
|
||||
const grammar = await Bun.file(file).text();
|
||||
|
||||
const parserSrc = peggy.generate(grammar, {
|
||||
format: 'commonjs',
|
||||
plugins: [tspegjs],
|
||||
output: 'source',
|
||||
});
|
||||
|
||||
await Bun.write(output, parserSrc);
|
||||
};
|
364
src/parser/grammar.pegjs
Normal file
364
src/parser/grammar.pegjs
Normal file
@ -0,0 +1,364 @@
|
||||
Program
|
||||
= exprs:(ContinuationExpression / _)* {
|
||||
return exprs.filter(x => !Array.isArray(x));
|
||||
}
|
||||
|
||||
ContinuationExpression
|
||||
= RecordExpression
|
||||
/ SelectExpression
|
||||
/ OffsetExpression
|
||||
/ ApplicationExpression
|
||||
/ FixExpression
|
||||
/ SwitchExpression
|
||||
/ PrimitiveOperationExpression
|
||||
|
||||
SelectExpression
|
||||
= SELECT
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
select:Integer
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
val:Value
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
bind:Identifier
|
||||
_?
|
||||
continuation:ContinuationExpression
|
||||
_?
|
||||
RPAREN { return { select, val, bind, continuation }; }
|
||||
|
||||
OffsetExpression
|
||||
= OFFSET
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
offset:Integer
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
val:Value
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
bind:Identifier
|
||||
_?
|
||||
continuation:ContinuationExpression
|
||||
_?
|
||||
RPAREN { return { offset, val, bind, continuation }; }
|
||||
|
||||
IdentifierList
|
||||
= LBRACKET
|
||||
_?
|
||||
identifiers:(ident:Identifier _? COMMA _?)*
|
||||
_?
|
||||
lastIdent:Identifier?
|
||||
_?
|
||||
RBRACKET {
|
||||
return identifiers.length || lastIdent
|
||||
? [...identifiers.map(x => x.ident), lastIdent]
|
||||
: [];
|
||||
}
|
||||
|
||||
ValueList
|
||||
= LBRACKET
|
||||
_?
|
||||
values:(value:Value _? COMMA _?)*
|
||||
_?
|
||||
lastValue:Value?
|
||||
_?
|
||||
RBRACKET {
|
||||
return values.length || lastValue
|
||||
? [...values.map(x => x.value), lastValue]
|
||||
: [];
|
||||
}
|
||||
|
||||
SwitchExpression
|
||||
= SWITCH
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
switchIndex:Value
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
continuations:ContinuationList
|
||||
_?
|
||||
RPAREN { return { switchIndex, continuations }; }
|
||||
|
||||
ApplicationExpression
|
||||
= APP _? LPAREN _? fn:Value _? COMMA _? args:ValueList _? RPAREN {
|
||||
return { fn, args };
|
||||
}
|
||||
|
||||
FixBinding
|
||||
= LPAREN
|
||||
_?
|
||||
fn:Identifier
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
args:IdentifierList
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
continuation:ContinuationExpression
|
||||
_?
|
||||
RPAREN
|
||||
|
||||
FixBindingList
|
||||
= LBRACKET
|
||||
_
|
||||
bindings:(binding:FixBinding _? COMMA _?)*
|
||||
_?
|
||||
lastBinding:FixBinding?
|
||||
_?
|
||||
RBRACKET {
|
||||
return bindings.length || lastBinding
|
||||
? [...bindings.map(x => x.binding), lastBinding]
|
||||
: [];
|
||||
}
|
||||
|
||||
FixExpression
|
||||
= FIX
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
fixBindings:FixBindingList
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
continuation:ContinuationExpression
|
||||
_?
|
||||
RPAREN { return { fixBindings, continuation }; }
|
||||
|
||||
ContinuationList
|
||||
= LBRACKET
|
||||
_?
|
||||
continuations:(continuation:ContinuationExpression _? COMMA _?)*
|
||||
_?
|
||||
lastContinuation:ContinuationExpression?
|
||||
_?
|
||||
RBRACKET {
|
||||
return lastContinuation || continuations.length
|
||||
? [...continuations.map(x => x.continuation), lastContinuation]
|
||||
: [];
|
||||
}
|
||||
|
||||
PrimitiveOperationExpression
|
||||
= PRIMOP
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
opr:PrimitiveOperation
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
operands:ValueList
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
resultBindings:IdentifierList
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
continuations:ContinuationList
|
||||
_?
|
||||
RPAREN { return { opr, operands, resultBindings, continuations }; }
|
||||
|
||||
RecordExpressionTuple
|
||||
= LPAREN
|
||||
_?
|
||||
variable:VarStatement
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
offset:OffsetStatement
|
||||
_?
|
||||
RPAREN { return { variable, offset }; }
|
||||
|
||||
RecordExpressionTupleList
|
||||
= LBRACKET
|
||||
_?
|
||||
records:(record:RecordExpressionTuple _? COMMA _?)*
|
||||
_?
|
||||
lastRecord:RecordExpressionTuple?
|
||||
_?
|
||||
RBRACKET {
|
||||
return records.length || lastRecord
|
||||
? [...records.map(x => x.record), lastRecord]
|
||||
: [];
|
||||
}
|
||||
|
||||
RecordExpression
|
||||
= RECORD
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
records:RecordExpressionTupleList
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
address:Literal
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
body:ContinuationExpression
|
||||
_?
|
||||
RPAREN {
|
||||
return {
|
||||
records,
|
||||
address,
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
||||
Value
|
||||
= VarStatement
|
||||
/ LabelStatement
|
||||
/ IntStatement
|
||||
/ RealStatement
|
||||
/ StringStatement
|
||||
|
||||
VarStatement = VAR _ ident:Identifier { return ident; }
|
||||
|
||||
LabelStatement = LABEL _ ident:Identifier { return ident; }
|
||||
|
||||
IntStatement = INT _ int:Integer { return int; }
|
||||
|
||||
RealStatement = REAL _ real:Real { return real; }
|
||||
|
||||
StringStatement = STRING _ string:QuotedString { return string; }
|
||||
|
||||
AccessStatement
|
||||
= OffsetStatement
|
||||
/ SelectStatement
|
||||
|
||||
OffsetStatement = OFFP _ offset:Integer { return offset; }
|
||||
|
||||
SelectStatement = SELP _ offset:Integer { return offset; }
|
||||
|
||||
Identifier
|
||||
= name:([A-Za-z] (LETTER / DIGIT / SAFE_SYMBOL)*) {
|
||||
return { name: name[0] + name[1].join('') };
|
||||
}
|
||||
|
||||
PrimitiveOperation
|
||||
= ArithmeticOperation
|
||||
/ ComparisonOperation
|
||||
/ BitOperation
|
||||
/ StoreOperation
|
||||
|
||||
StoreOperation
|
||||
= STORE
|
||||
/ UPDATE
|
||||
/ MAKEREF
|
||||
/ MAKEREFUNBOXED
|
||||
/ UNBOXED_UPDATE
|
||||
/ BOXED
|
||||
/ SUBSCRIPT
|
||||
|
||||
ArithmeticOperation
|
||||
= "+"
|
||||
/ "-"
|
||||
/ "/"
|
||||
/ "*"
|
||||
/ "**"
|
||||
|
||||
BitOperation
|
||||
= ">>"
|
||||
/ "<<"
|
||||
/ "~"
|
||||
/ "^"
|
||||
|
||||
ComparisonOperation
|
||||
= "=="
|
||||
/ "<="
|
||||
/ ">="
|
||||
/ "!="
|
||||
/ "!"
|
||||
/ ">"
|
||||
/ "<"
|
||||
|
||||
Integer = digits:[0-9]+ !"." { return parseInt(digits.join(''), 10); }
|
||||
|
||||
QuotedString
|
||||
= "'" content:[^']* "'" { return content.join(''); }
|
||||
/ "\"" content:[^"]* "\"" { return content.join(''); }
|
||||
|
||||
Real
|
||||
= value:("-"? [0-9]+ "." [0-9]+) {
|
||||
return parseFloat(
|
||||
value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''),
|
||||
);
|
||||
}
|
||||
|
||||
Literal
|
||||
= Real
|
||||
/ QuotedString
|
||||
/ Integer
|
||||
|
||||
OFFSET = "OFFSET"
|
||||
|
||||
OFFP = "OFFp"
|
||||
|
||||
SELP = "SELp"
|
||||
|
||||
VAR = "VAR"
|
||||
|
||||
INT = "INT"
|
||||
|
||||
REAL = "REAL"
|
||||
|
||||
STRING = "STRING"
|
||||
|
||||
APP = "APP"
|
||||
|
||||
RECORD = "RECORD"
|
||||
|
||||
SELECT = "SELECT"
|
||||
|
||||
FIX = "FIX"
|
||||
|
||||
SWITCH = "SWITCH"
|
||||
|
||||
PRIMOP = "PRIMOP"
|
||||
|
||||
LABEL = "LABEL"
|
||||
|
||||
STORE = "store"
|
||||
|
||||
UPDATE = "update"
|
||||
|
||||
MAKEREF = "makeref"
|
||||
|
||||
MAKEREFUNBOXED = "makerefunboxed"
|
||||
|
||||
UNBOXED_UPDATE = "unboxedupdate"
|
||||
|
||||
SUBSCRIPT = "subscript"
|
||||
|
||||
BOXED = "boxed"
|
||||
|
||||
LETTER = [A-Za-z]
|
||||
|
||||
SAFE_SYMBOL = "_"
|
||||
|
||||
DIGIT = [0-9]
|
||||
|
||||
LBRACKET = "["
|
||||
|
||||
RBRACKET = "]"
|
||||
|
||||
COMMA = ","
|
||||
|
||||
EQUALS = "="
|
||||
|
||||
LPAREN = "("
|
||||
|
||||
RPAREN = ")"
|
||||
|
||||
_ = (" " / "\n" / "\t" / "\r\n")+
|
6
src/parser/index.ts
Normal file
6
src/parser/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './generate';
|
||||
export * from './parser';
|
||||
import * as peggy from './parser';
|
||||
|
||||
export const peggyParse = (source: string): peggy.FunctionDefinition[] =>
|
||||
peggy.parse(source);
|
5235
src/parser/parser.ts
Normal file
5235
src/parser/parser.ts
Normal file
File diff suppressed because it is too large
Load Diff
1
src/utils/exception.ts
Normal file
1
src/utils/exception.ts
Normal file
@ -0,0 +1 @@
|
||||
export class NotImplementedException extends Error {}
|
2
src/utils/index.ts
Normal file
2
src/utils/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './logger';
|
||||
export * from './exception';
|
51
src/utils/logger.ts
Normal file
51
src/utils/logger.ts
Normal file
@ -0,0 +1,51 @@
|
||||
export interface TracingLogger {
|
||||
info(log: string): void;
|
||||
warn(log: string): void;
|
||||
error(log: string): void;
|
||||
debug(log: string): void;
|
||||
|
||||
createChild(prefix: string): TracingLogger;
|
||||
}
|
||||
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
||||
|
||||
export class ConsoleTracingLogger implements TracingLogger {
|
||||
protected prefix: string;
|
||||
private levels: LogLevel[];
|
||||
|
||||
constructor(prefix: string, levels: LogLevel[] = ['warn', 'error']) {
|
||||
this.prefix = prefix;
|
||||
this.levels = levels;
|
||||
}
|
||||
|
||||
private makePrefix(level: LogLevel): string {
|
||||
return `[${new Date().toISOString()}] ${level} (${this.prefix}) > `;
|
||||
}
|
||||
|
||||
public info(log: string) {
|
||||
if (this.levels.includes('info'))
|
||||
console.log(this.makePrefix('info') + log);
|
||||
}
|
||||
|
||||
public warn(log: string) {
|
||||
if (this.levels.includes('warn'))
|
||||
console.warn(this.makePrefix('warn') + log);
|
||||
}
|
||||
|
||||
public error(log: string) {
|
||||
if (this.levels.includes('error'))
|
||||
console.error(this.makePrefix('error') + log);
|
||||
}
|
||||
|
||||
public debug(log: string) {
|
||||
if (this.levels.includes('debug'))
|
||||
console.debug(this.makePrefix('debug') + log);
|
||||
}
|
||||
|
||||
public createChild(prefix: string, levels?: LogLevel[]) {
|
||||
return new ConsoleTracingLogger(
|
||||
`${this.prefix} -> ${prefix}`,
|
||||
levels ?? this.levels,
|
||||
);
|
||||
}
|
||||
}
|
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@t/*": ["./test/*"]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user