From 03ff4649e4a999fe0d5274535ed9105af8d665cd Mon Sep 17 00:00:00 2001 From: Solo-steven Date: Fri, 8 Nov 2024 00:13:21 +0800 Subject: [PATCH 1/2] feat: impl simple generator --- package.json | 1 + web-infras/common/src/kind.ts | 2 +- web-infras/generator/.prettierignore | 6 + web-infras/generator/.prettierrc.json | 21 ++ web-infras/generator/README.md | 2 + web-infras/generator/eslint.config.mjs | 21 ++ web-infras/generator/package.json | 41 +++ web-infras/generator/src/dev.ts | 8 + web-infras/generator/src/helper.ts | 74 +++++ web-infras/generator/src/index.ts | 29 ++ web-infras/generator/src/js/declaration.ts | 63 ++++ web-infras/generator/src/js/expression.ts | 328 +++++++++++++++++++++ web-infras/generator/src/js/index.ts | 4 + web-infras/generator/src/js/program.ts | 223 ++++++++++++++ web-infras/generator/src/js/statement.ts | 176 +++++++++++ web-infras/generator/tsconfig.json | 114 +++++++ yarn.lock | 327 +++++++++++++++++++- 17 files changed, 1437 insertions(+), 3 deletions(-) create mode 100644 web-infras/generator/.prettierignore create mode 100644 web-infras/generator/.prettierrc.json create mode 100644 web-infras/generator/README.md create mode 100644 web-infras/generator/eslint.config.mjs create mode 100644 web-infras/generator/package.json create mode 100644 web-infras/generator/src/dev.ts create mode 100644 web-infras/generator/src/helper.ts create mode 100644 web-infras/generator/src/index.ts create mode 100644 web-infras/generator/src/js/declaration.ts create mode 100644 web-infras/generator/src/js/expression.ts create mode 100644 web-infras/generator/src/js/index.ts create mode 100644 web-infras/generator/src/js/program.ts create mode 100644 web-infras/generator/src/js/statement.ts create mode 100644 web-infras/generator/tsconfig.json diff --git a/package.json b/package.json index 7d01ebb3..1400bd51 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "workspaces": [ "web-infras/parser", "web-infras/common", + "web-infras/generator", "web-infras/analyzer", "website/frontend" ], diff --git a/web-infras/common/src/kind.ts b/web-infras/common/src/kind.ts index 40d73f29..cf64e92e 100644 --- a/web-infras/common/src/kind.ts +++ b/web-infras/common/src/kind.ts @@ -590,7 +590,7 @@ export const SytaxKindsMapLexicalLiteral: Record = { [SyntaxKinds.BitwiseRightShiftFillAssginOperator]: ">>>=", // >>>= [SyntaxKinds.NullishAssignOperator]: "??=", // ========= Token (Maybe Punctuator and Operator) ===== - [SyntaxKinds.CommaToken]: "CommaToken", + [SyntaxKinds.CommaToken]: ",", // ========== Punctuator =========== [SyntaxKinds.BracesLeftPunctuator]: "{", // { [SyntaxKinds.BracesRightPunctuator]: "}", // } diff --git a/web-infras/generator/.prettierignore b/web-infras/generator/.prettierignore new file mode 100644 index 00000000..3764802a --- /dev/null +++ b/web-infras/generator/.prettierignore @@ -0,0 +1,6 @@ +## tsconfig +**/tsconfig.json +## rollup config +**/rollup.config.js +## README +**/README.md diff --git a/web-infras/generator/.prettierrc.json b/web-infras/generator/.prettierrc.json new file mode 100644 index 00000000..57a55915 --- /dev/null +++ b/web-infras/generator/.prettierrc.json @@ -0,0 +1,21 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "experimentalTernaries": false, + "singleQuote": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "all", + "singleAttributePerLine": false, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "insertPragma": false, + "printWidth": 110, + "requirePragma": false, + "tabWidth": 2, + "useTabs": false, + "embeddedLanguageFormatting": "auto" +} diff --git a/web-infras/generator/README.md b/web-infras/generator/README.md new file mode 100644 index 00000000..39f72fd3 --- /dev/null +++ b/web-infras/generator/README.md @@ -0,0 +1,2 @@ +# Web Infra Generator +Simple generator, generator JavaScript code from AST, not implement all kind of ast(too lazy), not contain sourcemap in current stage. diff --git a/web-infras/generator/eslint.config.mjs b/web-infras/generator/eslint.config.mjs new file mode 100644 index 00000000..8e2b8991 --- /dev/null +++ b/web-infras/generator/eslint.config.mjs @@ -0,0 +1,21 @@ +// @ts-check + +import eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; + +export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, { + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + }, +}); diff --git a/web-infras/generator/package.json b/web-infras/generator/package.json new file mode 100644 index 00000000..ac9e7206 --- /dev/null +++ b/web-infras/generator/package.json @@ -0,0 +1,41 @@ +{ + "name": "web-infra-generator", + "packageManager": "yarn@3.6.3", + "scripts": { + "build": "rollup --config --bundleConfigAsCjs rollup.config.js", + "dev": "ts-node --swc ./src/dev.ts", + "format": "yarn prettier . --check", + "format:write": "yarn prettier . --write", + "lint": "yarn eslint", + "lint:fix": "yarn eslint --fix" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@rollup/plugin-typescript": "^11.1.5", + "@swc/core": "^1.7.10", + "@types/eslint": "^9", + "@types/eslint__js": "^8.42.3", + "chalk": "4.1.2", + "eslint": "^9.14.0", + "nodemon": "^3.0.1", + "prettier": "^3.3.2", + "rollup": "^4.1.4", + "rollup-plugin-dts": "^6.1.0", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "tslib": "^2.6.2", + "typescript": "^5.6.3", + "typescript-eslint": "^8.13.0", + "web-infra-common": "workspace:*", + "web-infra-parser": "workspace:*" + }, + "lint-staged": { + "*.{ts}": [ + "yarn format:write", + "yarn lint:fix" + ], + "*.md": [ + "yarn format:write" + ] + } +} diff --git a/web-infras/generator/src/dev.ts b/web-infras/generator/src/dev.ts new file mode 100644 index 00000000..5c0db65e --- /dev/null +++ b/web-infras/generator/src/dev.ts @@ -0,0 +1,8 @@ +import { parse } from "web-infra-parser"; +import { Generaotr } from "@/src/index"; +const ast = parse("function a(c) { const cc = 10+c; return cc; }"); +const generator = new Generaotr(); + +generator.genProgram(ast); + +console.log(generator.code); diff --git a/web-infras/generator/src/helper.ts b/web-infras/generator/src/helper.ts new file mode 100644 index 00000000..0cb39359 --- /dev/null +++ b/web-infras/generator/src/helper.ts @@ -0,0 +1,74 @@ +import { SyntaxKinds, SytaxKindsMapLexicalLiteral } from "web-infra-common"; +import { Generaotr } from "@/src/index"; +/** + * Write a syntax token, token kind can not be + * - AST node + * - Literal + * - Comment + */ +export function writeToken(this: Generaotr, tokenKind: SyntaxKinds) { + if (tokenKind > 10107) { + throw new Error(); + } + const literal = SytaxKindsMapLexicalLiteral[tokenKind]; + this.code += literal; + return; +} +/** + * Write a space in current level, one level is 2 space. + */ +export function writePrefixSpace(this: Generaotr) { + for (let i = 0; i < this.spaceLevel * 2; ++i) { + this.code += " "; + } +} +/** + * Write a line terminator. + */ +export function writeLineTerminator(this: Generaotr) { + this.code += "\n"; +} +/** + * Enter another space for print. + */ +export function enterSpaceBlock(this: Generaotr) { + this.spaceLevel++; +} +/** + * Exit space scope. + */ +export function exitSpaceBlock(this: Generaotr) { + this.spaceLevel--; +} +/** + * Write something with `()` paran. + */ +export function writeWithParan(this: Generaotr, callback: () => void) { + this.writeToken(SyntaxKinds.ParenthesesLeftPunctuator); + callback(); + this.writeToken(SyntaxKinds.ParenthesesRightPunctuator); +} +/** + * Write something with `{}` wrapper. + * - changeline: add line terminator after `{`. + */ +export function writeWithBraces(this: Generaotr, changeLine: boolean, callback: () => void) { + this.writeToken(SyntaxKinds.BracesLeftPunctuator); + if (changeLine) this.writeLineTerminator(); + this.enterSpaceBlock(); + callback(); + this.exitSpaceBlock(); + this.writeToken(SyntaxKinds.BracesRightPunctuator); +} +/** + * Write a contextual keyword, basicly mean anything. + */ +export function writeRawString(this: Generaotr, keyword: string) { + this.code += keyword; +} +/** + * Write a space. + */ +export function writeSpace(this: Generaotr) { + this.code += " "; +} diff --git a/web-infras/generator/src/index.ts b/web-infras/generator/src/index.ts new file mode 100644 index 00000000..bc3f5744 --- /dev/null +++ b/web-infras/generator/src/index.ts @@ -0,0 +1,29 @@ +import * as HelperImpl from "./helper"; +import * as JSImpl from "./js"; + +export class Generaotr { + code: string; + spaceLevel: number; + constructor() { + this.code = ""; + this.spaceLevel = 0; + } +} + +type JSImplType = typeof JSImpl; +type HelperImpType = typeof HelperImpl; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function bindingParserMethod(methods: any) { + Object.entries(methods).forEach(([name, method]) => { + // @ts-expect-error implement in JS prototype + Generaotr.prototype[name] = method; + }); +} + +bindingParserMethod(HelperImpl); +bindingParserMethod(JSImpl); + +declare module "./index" { + interface Generaotr extends JSImplType, HelperImpType {} +} diff --git a/web-infras/generator/src/js/declaration.ts b/web-infras/generator/src/js/declaration.ts new file mode 100644 index 00000000..191b9242 --- /dev/null +++ b/web-infras/generator/src/js/declaration.ts @@ -0,0 +1,63 @@ +import { Generaotr } from "@/src/index"; +import { + SyntaxKinds, + Pattern, + FunctionBody, + FunctionDeclaration, + VariableDeclaration, + VariableDeclarator, +} from "web-infra-common"; + +export function genVariableDeclaration(this: Generaotr, variableDeclaration: VariableDeclaration) { + this.writeRawString(variableDeclaration.variant); + this.writeSpace(); + this.genVariableDeclarator(variableDeclaration.declarations[0]); + for (const declarator of variableDeclaration.declarations.slice(1)) { + this.writeToken(SyntaxKinds.CommaToken); + this.genVariableDeclarator(declarator); + } + this.writeToken(SyntaxKinds.SemiPunctuator); + this.writeLineTerminator(); +} +export function genVariableDeclarator(this: Generaotr, declarator: VariableDeclarator) { + this.genModuleItem(declarator.id); + if (declarator.init) { + this.writeSpace(); + this.writeToken(SyntaxKinds.AssginOperator); + this.writeSpace(); + this.genModuleItem(declarator.init); + } +} +export function genFunctionDeclaration(this: Generaotr, functionDeclar: FunctionDeclaration) { + if (functionDeclar.async) { + this.writeRawString("async"); + this.writeSpace(); + } + if (functionDeclar.generator) { + this.writeToken(SyntaxKinds.MultiplyOperator); + this.writeSpace(); + } + this.writeToken(SyntaxKinds.FunctionKeyword); + this.writeSpace(); + this.genIdentifier(functionDeclar.name); + this.genFunctionParam(functionDeclar.params); + this.writeSpace(); + this.genFunctionBody(functionDeclar.body); +} + +export function genFunctionParam(this: Generaotr, params: Pattern[]) { + this.writeWithParan(() => { + params.forEach((param, index) => { + this.genModuleItem(param); + if (index !== params.length - 1) this.writeToken(SyntaxKinds.CommaToken); + }); + }); +} +export function genFunctionBody(this: Generaotr, body: FunctionBody) { + this.writeWithBraces(true, () => { + for (const statementItem of body.body) { + this.writePrefixSpace(); + this.genModuleItem(statementItem); + } + }); +} diff --git a/web-infras/generator/src/js/expression.ts b/web-infras/generator/src/js/expression.ts new file mode 100644 index 00000000..3238614f --- /dev/null +++ b/web-infras/generator/src/js/expression.ts @@ -0,0 +1,328 @@ +import { Generaotr } from "@/src/index"; +import { + SyntaxKinds, + Super, + Import, + ThisExpression, + Identifier, + PrivateName, + NumberLiteral, + StringLiteral, + SpreadElement, + AwaitExpression, + NewExpression, + MemberExpression, + CallExpression, + ChainExpression, + UpdateExpression, + UnaryExpression, + BinaryExpression, + ConditionalExpression, + YieldExpression, + AssigmentExpression, + SequenceExpression, + NullLiteral, + UndefinbedLiteral, + BoolLiteral, + RegexLiteral, + ArrayExpression, + ObjectExpression, + ObjectProperty, + ObjectAccessor, + PropertyName, + ObjectMethodDefinition, + FunctionExpression, + ArrorFunctionExpression, +} from "web-infra-common"; + +export function writeParanIfNeed(this: Generaotr, isParan: boolean | undefined, callback: () => void) { + if (isParan) { + this.writeWithParan(callback); + } else { + callback(); + } +} +export function genSuper(this: Generaotr, superExpr: Super) { + this.writeParanIfNeed(superExpr.parentheses, () => { + this.writeToken(SyntaxKinds.SuperKeyword); + }); +} +export function genImport(this: Generaotr, importExpr: Import) { + this.writeParanIfNeed(importExpr.parentheses, () => { + this.writeToken(SyntaxKinds.ImportKeyword); + }); +} +export function genThisExpression(this: Generaotr, thisExpr: ThisExpression) { + this.writeParanIfNeed(thisExpr.parentheses, () => { + this.writeToken(SyntaxKinds.ThisKeyword); + }); +} +export function genIdentifier(this: Generaotr, identifer: Identifier) { + this.writeParanIfNeed(identifer.parentheses, () => { + this.writeRawString(identifer.name); + }); +} +export function genPrivateName(this: Generaotr, privateName: PrivateName) { + this.writeParanIfNeed(privateName.parentheses, () => { + this.writeToken(SyntaxKinds.HashTagPunctuator); + this.writeRawString(privateName.name); + }); +} +export function genNumberLiteral(this: Generaotr, numberLiteral: NumberLiteral) { + this.writeParanIfNeed(numberLiteral.parentheses, () => { + this.writeRawString(numberLiteral.rawValue); + }); +} +export function genStringLiteral(this: Generaotr, stringLiteral: StringLiteral) { + this.writeParanIfNeed(stringLiteral.parentheses, () => { + this.writeRawString(stringLiteral.value); + }); +} +export function genBoolLiteral(this: Generaotr, boolLiteral: BoolLiteral) { + this.writeParanIfNeed(boolLiteral.parentheses, () => { + this.writeRawString(boolLiteral.value.toString()); + }); +} +export function genNullLiteral(this: Generaotr, nullLiteral: NullLiteral) { + this.writeParanIfNeed(nullLiteral.parentheses, () => { + this.writeToken(SyntaxKinds.NullKeyword); + }); +} +export function genUndefiniedLiteral(this: Generaotr, undefinbedLiteral: UndefinbedLiteral) { + this.writeParanIfNeed(undefinbedLiteral.parentheses, () => { + this.writeToken(SyntaxKinds.UndefinedKeyword); + }); +} +export function genRegexLiteral(this: Generaotr, regexLiteral: RegexLiteral) { + this.writeParanIfNeed(regexLiteral.parentheses, () => { + this.writeRawString(`/${regexLiteral.pattern}/`); + this.writeRawString(regexLiteral.pattern); + }); +} +export function genObjectExpression(this: Generaotr, objectExpression: ObjectExpression) { + this.writeParanIfNeed(objectExpression.parentheses, () => { + this.writeWithBraces(true, () => { + for (const def of objectExpression.properties) { + this.writePrefixSpace(); + this.genModuleItem(def); + this.writeToken(SyntaxKinds.CommaToken); + this.writeLineTerminator(); + } + }); + }); +} +export function genObjectProperty(this: Generaotr, objectProperty: ObjectProperty) { + this.genPropertyName(objectProperty.key, objectProperty.computed); + this.writeToken(SyntaxKinds.ColonPunctuator); + this.writeSpace(); + if (objectProperty.value) { + this.genModuleItem(objectProperty.value); + } +} +export function genPropertyName(this: Generaotr, propertyName: PropertyName, isComputed: boolean) { + if (isComputed) { + this.writeToken(SyntaxKinds.BracketLeftPunctuator); + this.genModuleItem(propertyName); + this.writeToken(SyntaxKinds.BracesRightPunctuator); + } else { + this.genModuleItem(propertyName); + } +} +export function genObjectMethod(this: Generaotr, objectMethod: ObjectMethodDefinition) { + if (objectMethod.async) { + this.writeRawString("async"); + this.writeSpace(); + } + if (objectMethod.generator) { + this.writeToken(SyntaxKinds.MultiplyOperator); + this.writeSpace(); + } + this.genPropertyName(objectMethod.key, objectMethod.computed); + this.genFunctionParam(objectMethod.params); + this.genFunctionBody(objectMethod.body); +} +export function genObjectAccessor(this: Generaotr, objectAccessor: ObjectAccessor) { + this.writeRawString(objectAccessor.type); + this.writeSpace(); + this.genPropertyName(objectAccessor.key, objectAccessor.computed); + this.genFunctionParam(objectAccessor.params); + this.genFunctionBody(objectAccessor.body); +} +export function genArrayExpression(this: Generaotr, arrayExpression: ArrayExpression) { + this.writeParanIfNeed(arrayExpression.parentheses, () => { + this.writeToken(SyntaxKinds.BracketLeftPunctuator); + if (arrayExpression.elements[0]) this.genModuleItem(arrayExpression.elements[0]); + for (const ele of arrayExpression.elements.slice(1)) { + this.writeToken(SyntaxKinds.CommaToken); + if (ele) this.genModuleItem(ele); + } + this.writeToken(SyntaxKinds.BracketRightPunctuator); + }); +} +export function genFunctionExpression(this: Generaotr, functionExpression: FunctionExpression) { + this.writeParanIfNeed(functionExpression.parentheses, () => { + if (functionExpression.async) { + this.writeRawString("async"); + this.writeSpace(); + } + if (functionExpression.generator) { + this.writeToken(SyntaxKinds.MultiplyOperator); + this.writeSpace(); + } + this.writeToken(SyntaxKinds.FunctionKeyword); + if (functionExpression.name) { + this.writeSpace(); + this.genIdentifier(functionExpression.name); + } + this.genFunctionParam(functionExpression.params); + this.writeSpace(); + this.genFunctionBody(functionExpression.body); + }); +} +export function genArrowFunctionExpression(this: Generaotr, arrowExpr: ArrorFunctionExpression) { + this.writeParanIfNeed(arrowExpr.parentheses, () => { + if (arrowExpr.async) { + this.writeRawString("async"); + this.writeSpace(); + } + this.genFunctionParam(arrowExpr.arguments); + this.writeSpace(); + this.writeToken(SyntaxKinds.ArrowOperator); + this.writeSpace(); + this.genModuleItem(arrowExpr.body); + }); +} +export function genSpreadElement(this: Generaotr, spreadElement: SpreadElement) { + this.writeParanIfNeed(spreadElement.parentheses, () => { + this.writeToken(SyntaxKinds.SpreadOperator); + this.genModuleItem(spreadElement.argument); + }); +} +export function genAwaitExpression(this: Generaotr, awaitElement: AwaitExpression) { + this.writeParanIfNeed(awaitElement.parentheses, () => { + this.writeRawString("await"); + this.writeSpace(); + this.genModuleItem(awaitElement.argument); + }); +} +export function genNewExpression(this: Generaotr, newExpression: NewExpression) { + this.writeParanIfNeed(newExpression.parentheses, () => { + this.writeToken(SyntaxKinds.NewKeyword); + this.writeSpace(); + this.genModuleItem(newExpression.callee); + this.writeWithParan(() => { + for (const argu of newExpression.arguments) { + this.genModuleItem(argu); + } + }); + }); +} +export function genMemberExpression(this: Generaotr, memberExpression: MemberExpression) { + this.writeParanIfNeed(memberExpression.parentheses, () => { + this.genModuleItem(memberExpression.object); + if (memberExpression.computed) { + if (memberExpression.optional) { + this.writeToken(SyntaxKinds.QustionDotOperator); + } + this.writeToken(SyntaxKinds.BracketLeftPunctuator); + this.genModuleItem(memberExpression.property); + this.writeToken(SyntaxKinds.BracketRightPunctuator); + } else { + if (memberExpression.optional) { + this.writeToken(SyntaxKinds.QustionDotOperator); + } else { + this.writeToken(SyntaxKinds.DotOperator); + } + this.genModuleItem(memberExpression.property); + } + }); +} +export function genCallExpression(this: Generaotr, callExpression: CallExpression) { + this.writeParanIfNeed(callExpression.parentheses, () => { + this.genModuleItem(callExpression.callee); + if (callExpression.optional) { + this.writeToken(SyntaxKinds.QustionDotOperator); + } + this.writeWithParan(() => { + for (const item of callExpression.arguments) { + this.genModuleItem(item); + } + }); + }); +} +export function genChainExpression(this: Generaotr, chainExpression: ChainExpression) { + this.writeParanIfNeed(chainExpression.parentheses, () => { + this.genModuleItem(chainExpression.expression); + }); +} +export function genUpdateExpression(this: Generaotr, updateExpression: UpdateExpression) { + this.writeParanIfNeed(updateExpression.parentheses, () => { + if (updateExpression.prefix) { + this.writeToken(updateExpression.operator); + this.writeSpace(); + this.genModuleItem(updateExpression.argument); + } else { + this.genModuleItem(updateExpression.argument); + this.writeSpace(); + this.writeToken(updateExpression.operator); + } + }); +} +export function genUnaryExpression(this: Generaotr, unaryExpression: UnaryExpression) { + this.writeParanIfNeed(unaryExpression.parentheses, () => { + this.writeToken(unaryExpression.operator); + this.writeSpace(); + this.genModuleItem(unaryExpression.argument); + }); +} +export function genBinaryExpression(this: Generaotr, binaryExpression: BinaryExpression) { + this.writeParanIfNeed(binaryExpression.parentheses, () => { + this.genModuleItem(binaryExpression.left); + this.writeSpace(); + this.writeToken(binaryExpression.operator); + this.writeSpace(); + this.genModuleItem(binaryExpression.right); + }); +} +export function genConditionalExpression(this: Generaotr, conditionalExpression: ConditionalExpression) { + this.writeParanIfNeed(conditionalExpression.parentheses, () => { + this.genModuleItem(conditionalExpression.test); + this.writeToken(SyntaxKinds.QustionOperator); + this.writeSpace(); + this.genModuleItem(conditionalExpression.consequnce); + this.writeSpace(); + this.writeToken(SyntaxKinds.ColonPunctuator); + this.writeSpace(); + this.genModuleItem(conditionalExpression.alter); + }); +} +export function genYieldExpression(this: Generaotr, yeildExpression: YieldExpression) { + this.writeParanIfNeed(yeildExpression.parentheses, () => { + this.writeToken(SyntaxKinds.YieldKeyword); + if (yeildExpression.delegate) { + this.writeToken(SyntaxKinds.MultiplyOperator); + } + this.writeSpace(); + if (yeildExpression.argument) { + this.genModuleItem(yeildExpression.argument); + } + }); +} +export function genAssignmentExpression(this: Generaotr, assigmentExpression: AssigmentExpression) { + this.writeParanIfNeed(assigmentExpression.parentheses, () => { + this.genModuleItem(assigmentExpression.left); + this.writeSpace(); + this.writeToken(assigmentExpression.operator); + this.writeSpace(); + this.genModuleItem(assigmentExpression.right); + }); +} +export function genSequenceExpression(this: Generaotr, sequenceExpression: SequenceExpression) { + this.writeParanIfNeed(sequenceExpression.parentheses, () => { + this.genModuleItem(sequenceExpression.exprs[0]); + for (const expr of sequenceExpression.exprs.slice(1)) { + this.writeToken(SyntaxKinds.CommaToken); + this.genModuleItem(expr); + } + }); +} diff --git a/web-infras/generator/src/js/index.ts b/web-infras/generator/src/js/index.ts new file mode 100644 index 00000000..8dfa4450 --- /dev/null +++ b/web-infras/generator/src/js/index.ts @@ -0,0 +1,4 @@ +export * from "./program"; +export * from "./declaration"; +export * from "./statement"; +export * from "./expression"; diff --git a/web-infras/generator/src/js/program.ts b/web-infras/generator/src/js/program.ts new file mode 100644 index 00000000..c2671c05 --- /dev/null +++ b/web-infras/generator/src/js/program.ts @@ -0,0 +1,223 @@ +import { Generaotr } from "../index"; +import { + SyntaxKinds, + ModuleItem, + Program, + IfStatement, + BlockStatement, + SwitchStatement, + ForInStatement, + ForOfStatement, + BreakStatement, + ContinueStatement, + ReturnStatement, + LabeledStatement, + WhileStatement, + DoWhileStatement, + TryStatement, + ThrowStatement, + DebuggerStatement, + WithStatement, + ExpressionStatement, + Super, + Import, + ThisExpression, + Identifier, + PrivateName, + StringLiteral, + NumberLiteral, + SpreadElement, + AwaitExpression, + NewExpression, + MemberExpression, + CallExpression, + ChainExpression, + UpdateExpression, + UnaryExpression, + ConditionalExpression, + YieldExpression, + AssigmentExpression, + SequenceExpression, + BinaryExpression, + FunctionDeclaration, + FunctionBody, + VariableDeclaration, + BoolLiteral, + NullLiteral, + UndefinbedLiteral, + RegexLiteral, + ObjectExpression, + ArrayExpression, + FunctionExpression, + ArrorFunctionExpression, +} from "web-infra-common"; + +export function genProgram(this: Generaotr, program: Program) { + for (const item of program.body) { + this.genModuleItem(item); + } +} + +export function genModuleItem(this: Generaotr, item: ModuleItem) { + switch (item.kind) { + /** + * Declaration + */ + case SyntaxKinds.VariableDeclaration: + this.genVariableDeclaration(item as VariableDeclaration); + break; + case SyntaxKinds.FunctionDeclaration: + this.genFunctionDeclaration(item as FunctionDeclaration); + break; + case SyntaxKinds.FunctionBody: + this.genFunctionBody(item as FunctionBody); + break; + /** + * Statement + */ + case SyntaxKinds.IfStatement: + this.genIfStatement(item as IfStatement); + break; + case SyntaxKinds.BlockStatement: + this.genBlockStatement(item as BlockStatement); + break; + case SyntaxKinds.SwitchStatement: + this.genSwitchStatement(item as SwitchStatement); + break; + case SyntaxKinds.ForInStatement: + this.genForInStatement(item as ForInStatement); + break; + case SyntaxKinds.ForOfStatement: + this.genForOfStatement(item as ForOfStatement); + break; + case SyntaxKinds.BreakStatement: + this.genBreakStatement(item as BreakStatement); + break; + case SyntaxKinds.ContinueStatement: + this.genContinueStatement(item as ContinueStatement); + break; + case SyntaxKinds.ReturnStatement: + this.genReturnStatement(item as ReturnStatement); + break; + case SyntaxKinds.LabeledStatement: + this.genLabeledStatement(item as LabeledStatement); + break; + case SyntaxKinds.WhileStatement: + this.genWhileStatment(item as WhileStatement); + break; + case SyntaxKinds.DoWhileStatement: + this.genDoWhileStatement(item as DoWhileStatement); + break; + case SyntaxKinds.TryStatement: + this.genTryStatement(item as TryStatement); + break; + case SyntaxKinds.ThrowStatement: + this.genThrowStatment(item as ThrowStatement); + break; + case SyntaxKinds.WithStatement: + this.genWithStatement(item as WithStatement); + break; + case SyntaxKinds.DebuggerKeyword: + this.genDebugerStatement(item as DebuggerStatement); + break; + case SyntaxKinds.ExpressionStatement: + this.genExpressionStatement(item as ExpressionStatement); + break; + /** + * Expression + */ + case SyntaxKinds.Super: + this.genSuper(item as Super); + break; + case SyntaxKinds.Import: + this.genImport(item as Import); + break; + case SyntaxKinds.ThisExpression: + this.genThisExpression(item as ThisExpression); + break; + case SyntaxKinds.Identifier: + this.genIdentifier(item as Identifier); + break; + case SyntaxKinds.PrivateName: + this.genPrivateName(item as PrivateName); + break; + case SyntaxKinds.DecimalLiteral: + case SyntaxKinds.NonOctalDecimalLiteral: + case SyntaxKinds.BinaryIntegerLiteral: + case SyntaxKinds.OctalIntegerLiteral: + case SyntaxKinds.HexIntegerLiteral: + case SyntaxKinds.LegacyOctalIntegerLiteral: + case SyntaxKinds.BinaryBigIntegerLiteral: + case SyntaxKinds.HexBigIntegerLiteral: + case SyntaxKinds.OctalBigIntegerLiteral: + case SyntaxKinds.DecimalBigIntegerLiteral: + this.genNumberLiteral(item as NumberLiteral); + break; + case SyntaxKinds.StringLiteral: + this.genStringLiteral(item as StringLiteral); + break; + case SyntaxKinds.BooleanLiteral: + this.genBoolLiteral(item as BoolLiteral); + break; + case SyntaxKinds.NullLiteral: + this.genNullLiteral(item as NullLiteral); + break; + case SyntaxKinds.UndefinedKeyword: + this.genUndefiniedLiteral(item as UndefinbedLiteral); + break; + case SyntaxKinds.RegexLiteral: + this.genRegexLiteral(item as RegexLiteral); + break; + case SyntaxKinds.ObjectExpression: + this.genObjectExpression(item as ObjectExpression); + break; + case SyntaxKinds.ArrayExpression: + this.genArrayExpression(item as ArrayExpression); + break; + case SyntaxKinds.FunctionExpression: + this.genFunctionExpression(item as FunctionExpression); + break; + case SyntaxKinds.ArrowFunctionExpression: + this.genArrowFunctionExpression(item as ArrorFunctionExpression); + break; + case SyntaxKinds.SpreadElement: + this.genSpreadElement(item as SpreadElement); + break; + case SyntaxKinds.AwaitExpression: + this.genAwaitExpression(item as AwaitExpression); + break; + case SyntaxKinds.NewExpression: + this.genNewExpression(item as NewExpression); + break; + case SyntaxKinds.MemberExpression: + this.genMemberExpression(item as MemberExpression); + break; + case SyntaxKinds.CallExpression: + this.genCallExpression(item as CallExpression); + break; + case SyntaxKinds.ChainExpression: + this.genChainExpression(item as ChainExpression); + break; + case SyntaxKinds.UpdateExpression: + this.genUpdateExpression(item as UpdateExpression); + break; + case SyntaxKinds.UnaryExpression: + this.genUnaryExpression(item as UnaryExpression); + break; + case SyntaxKinds.BinaryExpression: + this.genBinaryExpression(item as BinaryExpression); + break; + case SyntaxKinds.ConditionalExpression: + this.genConditionalExpression(item as ConditionalExpression); + break; + case SyntaxKinds.YieldExpression: + this.genYieldExpression(item as YieldExpression); + break; + case SyntaxKinds.AssigmentExpression: + this.genAssignmentExpression(item as AssigmentExpression); + break; + case SyntaxKinds.SequenceExpression: + this.genSequenceExpression(item as SequenceExpression); + break; + } +} diff --git a/web-infras/generator/src/js/statement.ts b/web-infras/generator/src/js/statement.ts new file mode 100644 index 00000000..f4263c48 --- /dev/null +++ b/web-infras/generator/src/js/statement.ts @@ -0,0 +1,176 @@ +import { + SyntaxKinds, + BlockStatement, + IfStatement, + SwitchStatement, + ForInStatement, + ForOfStatement, + BreakStatement, + ContinueStatement, + ReturnStatement, + LabeledStatement, + WhileStatement, + DoWhileStatement, + TryStatement, + ThrowStatement, + WithStatement, + CatchClause, + ExpressionStatement, + SwitchCase, + DebuggerStatement, +} from "web-infra-common"; +import { Generaotr } from "@/src/index"; + +export function genIfStatement(this: Generaotr, ifStatement: IfStatement) { + this.writeToken(SyntaxKinds.IfKeyword); + this.writeWithParan(() => { + this.genModuleItem(ifStatement.test); + }); + this.genModuleItem(ifStatement.conseqence); + if (ifStatement.alternative) { + this.writeToken(SyntaxKinds.ElseKeyword); + this.genModuleItem(ifStatement.alternative); + } +} +export function genBlockStatement(this: Generaotr, blockStatement: BlockStatement) { + this.writeWithBraces(true, () => { + for (const item of blockStatement.body) { + this.writePrefixSpace(); + this.genModuleItem(item); + } + }); +} +export function genSwitchStatement(this: Generaotr, switchStatement: SwitchStatement) { + this.writeToken(SyntaxKinds.SwitchKeyword); + this.writeWithParan(() => { + this.genModuleItem(switchStatement.discriminant); + }); + this.writeWithBraces(true, () => { + for (const singleCase of switchStatement.cases) { + this.writePrefixSpace(); + this.genModuleItem(singleCase); + } + }); + this.writeLineTerminator(); +} +export function genSwitchCase(this: Generaotr, switchCase: SwitchCase) { + if (switchCase.test) { + this.writeToken(SyntaxKinds.CaseKeyword); + this.genModuleItem(switchCase.test); + this.writeToken(SyntaxKinds.ColonPunctuator); + } else { + this.writeToken(SyntaxKinds.DefaultKeyword); + this.writeToken(SyntaxKinds.ColonPunctuator); + } + for (const item of switchCase.consequence) { + this.genModuleItem(item); + } +} +export function genForInStatement(this: Generaotr, forInStatement: ForInStatement) { + this.writeToken(SyntaxKinds.ForKeyword); + this.writeWithParan(() => { + this.genModuleItem(forInStatement.left); + this.writeRawString("of"); + this.genModuleItem(forInStatement.right); + }); + this.genModuleItem(forInStatement.body); + this.writeLineTerminator(); +} +export function genForOfStatement(this: Generaotr, forOfStatement: ForOfStatement) { + this.writeToken(SyntaxKinds.ForKeyword); + this.writeWithParan(() => { + this.genModuleItem(forOfStatement.left); + this.writeRawString("in"); + this.genModuleItem(forOfStatement.right); + }); + this.genModuleItem(forOfStatement.body); + this.writeLineTerminator(); +} +export function genBreakStatement(this: Generaotr, breakStatement: BreakStatement) { + this.writeToken(SyntaxKinds.BreakKeyword); + if (breakStatement.label) { + this.genModuleItem(breakStatement.label); + } + this.writeLineTerminator(); +} +export function genContinueStatement(this: Generaotr, continueStatement: ContinueStatement) { + this.writeToken(SyntaxKinds.ContinueKeyword); + if (continueStatement.label) { + this.genModuleItem(continueStatement.label); + } + this.writeLineTerminator(); +} +export function genReturnStatement(this: Generaotr, returnStatement: ReturnStatement) { + this.writeToken(SyntaxKinds.ReturnKeyword); + if (returnStatement.argu) this.genModuleItem(returnStatement.argu); + this.writeLineTerminator(); +} +export function genLabeledStatement(this: Generaotr, labeledStatement: LabeledStatement) { + this.genModuleItem(labeledStatement.label); + this.writeToken(SyntaxKinds.CommaToken); + this.genModuleItem(labeledStatement.body); +} +export function genWhileStatment(this: Generaotr, whileStatement: WhileStatement) { + this.writeToken(SyntaxKinds.WhileKeyword); + this.writeWithParan(() => { + this.genModuleItem(whileStatement.test); + }); + this.genModuleItem(whileStatement.body); +} +export function genDoWhileStatement(this: Generaotr, doWhileStatement: DoWhileStatement) { + this.writeToken(SyntaxKinds.DoKeyword); + this.genModuleItem(doWhileStatement.body); + this.writeToken(SyntaxKinds.WhileKeyword); + this.writeWithParan(() => { + this.genModuleItem(doWhileStatement.test); + }); +} +export function genTryStatement(this: Generaotr, tryStatement: TryStatement) { + this.writeToken(SyntaxKinds.TrueKeyword); + this.genBlockStatement(tryStatement.block); + this.writeToken(SyntaxKinds.CatchKeyword); + if (tryStatement.handler) { + this.genCatchClause(tryStatement.handler); + } + if (tryStatement.finalizer) { + this.writeToken(SyntaxKinds.FinallyKeyword); + this.writeWithBraces(true, () => { + for (const item of tryStatement.finalizer!.body) { + this.writePrefixSpace(); + this.genModuleItem(item); + } + }); + } +} +export function genCatchClause(this: Generaotr, catchClause: CatchClause) { + this.writeToken(SyntaxKinds.CatchKeyword); + if (catchClause.param) { + this.writeWithParan(() => { + this.genModuleItem(catchClause.param!); + }); + } + this.genBlockStatement(catchClause.body); +} +export function genThrowStatment(this: Generaotr, throwStatement: ThrowStatement) { + this.writeToken(SyntaxKinds.ThrowKeyword); + this.genModuleItem(throwStatement.argu); + this.writeLineTerminator(); +} +export function genWithStatement(this: Generaotr, withStatement: WithStatement) { + this.writeToken(SyntaxKinds.WithKeyword); + this.writeWithParan(() => { + this.genModuleItem(withStatement.object); + }); + this.writeToken(SyntaxKinds.ColonPunctuator); + this.genModuleItem(withStatement.body); +} +export function genDebugerStatement(this: Generaotr, _debuggerStatement: DebuggerStatement) { + this.writeToken(SyntaxKinds.DebuggerKeyword); + this.writeToken(SyntaxKinds.ColonPunctuator); + this.writeLineTerminator(); +} +export function genExpressionStatement(this: Generaotr, exprStatement: ExpressionStatement) { + this.genModuleItem(exprStatement.expr); + this.writeToken(SyntaxKinds.SemiPunctuator); + this.writeLineTerminator(); +} diff --git a/web-infras/generator/tsconfig.json b/web-infras/generator/tsconfig.json new file mode 100644 index 00000000..f82f1e9b --- /dev/null +++ b/web-infras/generator/tsconfig.json @@ -0,0 +1,114 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@/src/*": ["src/*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} diff --git a/yarn.lock b/yarn.lock index 22682419..d93f71bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -99,6 +99,13 @@ __metadata: languageName: node linkType: hard +"@eslint-community/regexpp@npm:^4.12.1": + version: 4.12.1 + resolution: "@eslint-community/regexpp@npm:4.12.1" + checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 + languageName: node + linkType: hard + "@eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" @@ -128,6 +135,13 @@ __metadata: languageName: node linkType: hard +"@eslint/core@npm:^0.7.0": + version: 0.7.0 + resolution: "@eslint/core@npm:0.7.0" + checksum: 10c0/3cdee8bc6cbb96ac6103d3ead42e59830019435839583c9eb352b94ed558bd78e7ffad5286dc710df21ec1e7bd8f52aa6574c62457a4dd0f01f3736fa4a7d87a + languageName: node + linkType: hard + "@eslint/eslintrc@npm:^2.1.4": version: 2.1.4 resolution: "@eslint/eslintrc@npm:2.1.4" @@ -169,6 +183,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:9.14.0, @eslint/js@npm:^9.14.0": + version: 9.14.0 + resolution: "@eslint/js@npm:9.14.0" + checksum: 10c0/a423dd435e10aa3b461599aa02f6cbadd4b5128cb122467ee4e2c798e7ca4f9bb1fce4dcea003b29b983090238cf120899c1af657cf86300b399e4f996b83ddc + languageName: node + linkType: hard + "@eslint/js@npm:9.9.0, @eslint/js@npm:^9.9.0": version: 9.9.0 resolution: "@eslint/js@npm:9.9.0" @@ -190,6 +211,32 @@ __metadata: languageName: node linkType: hard +"@eslint/plugin-kit@npm:^0.2.0": + version: 0.2.2 + resolution: "@eslint/plugin-kit@npm:0.2.2" + dependencies: + levn: "npm:^0.4.1" + checksum: 10c0/ec533ccc99f2ab003d6f64495cff853730fb7d8bc0eaf031ffccc68de7c34c74a2eda50dfa759cacfb409f014c98d306714c995348d5383c9d3140f9f80a5895 + languageName: node + linkType: hard + +"@humanfs/core@npm:^0.19.1": + version: 0.19.1 + resolution: "@humanfs/core@npm:0.19.1" + checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 + languageName: node + linkType: hard + +"@humanfs/node@npm:^0.16.6": + version: 0.16.6 + resolution: "@humanfs/node@npm:0.16.6" + dependencies: + "@humanfs/core": "npm:^0.19.1" + "@humanwhocodes/retry": "npm:^0.3.0" + checksum: 10c0/8356359c9f60108ec204cbd249ecd0356667359b2524886b357617c4a7c3b6aace0fd5a369f63747b926a762a88f8a25bc066fa1778508d110195ce7686243e1 + languageName: node + linkType: hard + "@humanwhocodes/config-array@npm:^0.11.13": version: 0.11.13 resolution: "@humanwhocodes/config-array@npm:0.11.13" @@ -222,6 +269,13 @@ __metadata: languageName: node linkType: hard +"@humanwhocodes/retry@npm:^0.4.0": + version: 0.4.0 + resolution: "@humanwhocodes/retry@npm:0.4.0" + checksum: 10c0/28dcf1ed70b28ae8bc07b268c457a02f6b53fe4591b73e31f6735e7673dfd9e662f24a69e065aada1a64311bf5692d93d4ef35aba849314e8a87a870ba3b47aa + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -745,7 +799,14 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*": +"@types/estree@npm:^1.0.6": + version: 1.0.6 + resolution: "@types/estree@npm:1.0.6" + checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a + languageName: node + linkType: hard + +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db @@ -811,6 +872,29 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.13.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.13.0" + "@typescript-eslint/type-utils": "npm:8.13.0" + "@typescript-eslint/utils": "npm:8.13.0" + "@typescript-eslint/visitor-keys": "npm:8.13.0" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/ee96515e9def17b0d1b8d568d4afcd21c5a8a1bc01bf2f30c4d1f396b41a2f49de3508f79c6231a137ca06943dd6933ac00032652190ab99a4e935ffef44df0b + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.2.0" @@ -834,6 +918,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/parser@npm:8.13.0" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.13.0" + "@typescript-eslint/types": "npm:8.13.0" + "@typescript-eslint/typescript-estree": "npm:8.13.0" + "@typescript-eslint/visitor-keys": "npm:8.13.0" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/fa04f6c417c0f72104e148f1d7ff53e04108d383550365a556fbfae5d2283484696235db522189e17bc49039946977078e324100cef991ca01f78704182624ad + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/parser@npm:8.2.0" @@ -880,6 +982,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/scope-manager@npm:8.13.0" + dependencies: + "@typescript-eslint/types": "npm:8.13.0" + "@typescript-eslint/visitor-keys": "npm:8.13.0" + checksum: 10c0/1924b3e740e244d98f8a99740b4196d23ae3263303b387c66db94e140455a3132e603a130f3f70fc71e37f4bda5d0c0c67224ae3911908b097ef3f972c136be4 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/scope-manager@npm:8.2.0" @@ -890,6 +1002,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/type-utils@npm:8.13.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:8.13.0" + "@typescript-eslint/utils": "npm:8.13.0" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/65319084616f3aea3d9f8dfab30c9b0a70de7314b445805016fdf0d0e39fe073eef2813c3e16c3e1c6a40462ba8eecfdbb12ab1e8570c3407a1cccdb69d4bc8b + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/type-utils@npm:8.2.0" @@ -912,6 +1039,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/types@npm:8.13.0" + checksum: 10c0/bd3f88b738a92b2222f388bcf831357ef8940a763c2c2eb1947767e1051dd2f8bee387020e8cf4c2309e4142353961b659abc2885e30679109a0488b0bfefc23 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/types@npm:8.2.0" @@ -938,6 +1072,25 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.13.0" + dependencies: + "@typescript-eslint/types": "npm:8.13.0" + "@typescript-eslint/visitor-keys": "npm:8.13.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/2d45bc5ed4ac352bea927167ac28ef23bd13b6ae352ff50e85cddfdc4b06518f1dd4ae5f2495e30d6f62d247987677a4e807065d55829ba28963908a821dc96d + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/typescript-estree@npm:8.2.0" @@ -957,6 +1110,20 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/utils@npm:8.13.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.13.0" + "@typescript-eslint/types": "npm:8.13.0" + "@typescript-eslint/typescript-estree": "npm:8.13.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + checksum: 10c0/3fc5a7184a949df5f5b64f6af039a1d21ef7fe15f3d88a5d485ccbb535746d18514751143993a5aee287228151be3e326baf8f899a0a0a93368f6f20857ffa6d + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/utils@npm:8.2.0" @@ -981,6 +1148,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.13.0": + version: 8.13.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.13.0" + dependencies: + "@typescript-eslint/types": "npm:8.13.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10c0/50b35f3cf673aaed940613f0007f7c4558a89ebef15c49824e65b6f084b700fbf01b01a4e701e24bbe651297a39678645e739acd255255f1603867a84bef0383 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:8.2.0": version: 8.2.0 resolution: "@typescript-eslint/visitor-keys@npm:8.2.0" @@ -1030,6 +1207,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.14.0": + version: 8.14.0 + resolution: "acorn@npm:8.14.0" + bin: + acorn: bin/acorn + checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7 + languageName: node + linkType: hard + "acorn@npm:^8.4.1": version: 8.10.0 resolution: "acorn@npm:8.10.0" @@ -2174,6 +2360,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:^8.2.0": + version: 8.2.0 + resolution: "eslint-scope@npm:8.2.0" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/8d2d58e2136d548ac7e0099b1a90d9fab56f990d86eb518de1247a7066d38c908be2f3df477a79cf60d70b30ba18735d6c6e70e9914dca2ee515a729975d70d6 + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" @@ -2188,6 +2384,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^4.2.0": + version: 4.2.0 + resolution: "eslint-visitor-keys@npm:4.2.0" + checksum: 10c0/2ed81c663b147ca6f578312919483eb040295bbab759e5a371953456c636c5b49a559883e2677112453728d66293c0a4c90ab11cab3428cf02a0236d2e738269 + languageName: node + linkType: hard + "eslint@npm:^8": version: 8.56.0 resolution: "eslint@npm:8.56.0" @@ -2236,6 +2439,56 @@ __metadata: languageName: node linkType: hard +"eslint@npm:^9.14.0": + version: 9.14.0 + resolution: "eslint@npm:9.14.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@eslint-community/regexpp": "npm:^4.12.1" + "@eslint/config-array": "npm:^0.18.0" + "@eslint/core": "npm:^0.7.0" + "@eslint/eslintrc": "npm:^3.1.0" + "@eslint/js": "npm:9.14.0" + "@eslint/plugin-kit": "npm:^0.2.0" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.0" + "@types/estree": "npm:^1.0.6" + "@types/json-schema": "npm:^7.0.15" + ajv: "npm:^6.12.4" + chalk: "npm:^4.0.0" + cross-spawn: "npm:^7.0.2" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^8.2.0" + eslint-visitor-keys: "npm:^4.2.0" + espree: "npm:^10.3.0" + esquery: "npm:^1.5.0" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^8.0.0" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + lodash.merge: "npm:^4.6.2" + minimatch: "npm:^3.1.2" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + text-table: "npm:^0.2.0" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + bin: + eslint: bin/eslint.js + checksum: 10c0/e1cbf571b75519ad0b24c27e66a6575e57cab2671ef5296e7b345d9ac3adc1a549118dcc74a05b651a7a13a5e61ebb680be6a3e04a80e1f22eba1931921b5187 + languageName: node + linkType: hard + "eslint@npm:^9.9.0": version: 9.9.0 resolution: "eslint@npm:9.9.0" @@ -2345,6 +2598,17 @@ __metadata: languageName: node linkType: hard +"espree@npm:^10.3.0": + version: 10.3.0 + resolution: "espree@npm:10.3.0" + dependencies: + acorn: "npm:^8.14.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.2.0" + checksum: 10c0/272beeaca70d0a1a047d61baff64db04664a33d7cfb5d144f84bc8a5c6194c6c8ebe9cc594093ca53add88baa23e59b01e69e8a0160ab32eac570482e165c462 + languageName: node + linkType: hard + "espree@npm:^9.6.0, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" @@ -2442,7 +2706,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.1": +"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.1, fast-glob@npm:^3.3.2": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" dependencies: @@ -5467,6 +5731,20 @@ __metadata: languageName: node linkType: hard +"typescript-eslint@npm:^8.13.0": + version: 8.13.0 + resolution: "typescript-eslint@npm:8.13.0" + dependencies: + "@typescript-eslint/eslint-plugin": "npm:8.13.0" + "@typescript-eslint/parser": "npm:8.13.0" + "@typescript-eslint/utils": "npm:8.13.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/a84958e7602360c4cb2e6227fd9aae19dd18cdf1a2cfd9ece2a81d54098f80454b5707e861e98547d0b2e5dae552b136aa6733b74f0dd743ca7bfe178083c441 + languageName: node + linkType: hard + "typescript-eslint@npm:^8.2.0": version: 8.2.0 resolution: "typescript-eslint@npm:8.2.0" @@ -5501,6 +5779,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.6.3": + version: 5.6.3 + resolution: "typescript@npm:5.6.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/44f61d3fb15c35359bc60399cb8127c30bae554cd555b8e2b46d68fa79d680354b83320ad419ff1b81a0bdf324197b29affe6cc28988cd6a74d4ac60c94f9799 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^5#optional!builtin": version: 5.3.3 resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin::version=5.3.3&hash=e012d7" @@ -5521,6 +5809,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.6.3#optional!builtin": + version: 5.6.3 + resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=b45daf" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ac8307bb06bbfd08ae7137da740769b7d8c3ee5943188743bb622c621f8ad61d244767480f90fbd840277fbf152d8932aa20c33f867dea1bb5e79b187ca1a92f + languageName: node + linkType: hard + "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -5648,6 +5946,31 @@ __metadata: languageName: unknown linkType: soft +"web-infra-generator@workspace:web-infras/generator": + version: 0.0.0-use.local + resolution: "web-infra-generator@workspace:web-infras/generator" + dependencies: + "@eslint/js": "npm:^9.14.0" + "@rollup/plugin-typescript": "npm:^11.1.5" + "@swc/core": "npm:^1.7.10" + "@types/eslint": "npm:^9" + "@types/eslint__js": "npm:^8.42.3" + chalk: "npm:4.1.2" + eslint: "npm:^9.14.0" + nodemon: "npm:^3.0.1" + prettier: "npm:^3.3.2" + rollup: "npm:^4.1.4" + rollup-plugin-dts: "npm:^6.1.0" + ts-node: "npm:^10.9.1" + tsconfig-paths: "npm:^4.2.0" + tslib: "npm:^2.6.2" + typescript: "npm:^5.6.3" + typescript-eslint: "npm:^8.13.0" + web-infra-common: "workspace:*" + web-infra-parser: "workspace:*" + languageName: unknown + linkType: soft + "web-infra-parser@workspace:*, web-infra-parser@workspace:web-infras/parser": version: 0.0.0-use.local resolution: "web-infra-parser@workspace:web-infras/parser" From 98dab5e180432de5968c628dae02ffd8bf52c5e2 Mon Sep 17 00:00:00 2001 From: Solo-steven Date: Sun, 17 Nov 2024 17:17:53 +0800 Subject: [PATCH 2/2] feat: implement simple bundler with limit scope --- .gitignore | 4 +- package.json | 3 +- web-infras/bundler/.gitignore | 2 + web-infras/bundler/.prettierignore | 6 + web-infras/bundler/.prettierrc.json | 21 ++ web-infras/bundler/README.md | 2 + web-infras/bundler/eslint.config.mjs | 27 ++ web-infras/bundler/package.json | 44 +++ web-infras/bundler/rollup.config.js | 32 ++ web-infras/bundler/src/chunkGraph/index.ts | 52 +++ .../chunkGraph/runtimeModuleResolver/const.ts | 19 ++ .../exportDeclarationTransformer.ts | 314 ++++++++++++++++++ .../importDeclarationTransformer.ts | 147 ++++++++ .../chunkGraph/runtimeModuleResolver/index.ts | 110 ++++++ .../chunkGraph/runtimeModuleResolver/utils.ts | 17 + web-infras/bundler/src/chunkGraph/type.ts | 4 + web-infras/bundler/src/config.ts | 4 + web-infras/bundler/src/depGraph/index.ts | 48 +++ web-infras/bundler/src/dev.ts | 15 + web-infras/bundler/src/utils/importVisitor.ts | 15 + .../bundler/src/utils/removeImportVisitor.ts | 64 ++++ web-infras/bundler/src/utils/resolvePath.ts | 12 + web-infras/bundler/tsconfig.build.json | 114 +++++++ web-infras/bundler/tsconfig.json | 115 +++++++ web-infras/generator/eslint.config.mjs | 38 ++- web-infras/generator/package.json | 4 +- web-infras/generator/rollup.config.js | 32 ++ web-infras/generator/src/dev.ts | 4 +- web-infras/generator/src/generator.ts | 32 ++ web-infras/generator/src/helper.ts | 27 +- web-infras/generator/src/index.ts | 33 +- web-infras/generator/src/js/declaration.ts | 13 +- web-infras/generator/src/js/expression.ts | 72 ++-- web-infras/generator/src/js/index.ts | 1 + web-infras/generator/src/js/pattern.ts | 53 +++ web-infras/generator/src/js/program.ts | 25 +- web-infras/generator/src/js/statement.ts | 43 +-- web-infras/generator/tsconfig.build.json | 114 +++++++ web-infras/generator/tsconfig.json | 2 +- web-infras/parser/tsconfig.json | 224 ++++++------- yarn.lock | 28 +- 41 files changed, 1700 insertions(+), 236 deletions(-) create mode 100644 web-infras/bundler/.gitignore create mode 100644 web-infras/bundler/.prettierignore create mode 100644 web-infras/bundler/.prettierrc.json create mode 100644 web-infras/bundler/README.md create mode 100644 web-infras/bundler/eslint.config.mjs create mode 100644 web-infras/bundler/package.json create mode 100644 web-infras/bundler/rollup.config.js create mode 100644 web-infras/bundler/src/chunkGraph/index.ts create mode 100644 web-infras/bundler/src/chunkGraph/runtimeModuleResolver/const.ts create mode 100644 web-infras/bundler/src/chunkGraph/runtimeModuleResolver/exportDeclarationTransformer.ts create mode 100644 web-infras/bundler/src/chunkGraph/runtimeModuleResolver/importDeclarationTransformer.ts create mode 100644 web-infras/bundler/src/chunkGraph/runtimeModuleResolver/index.ts create mode 100644 web-infras/bundler/src/chunkGraph/runtimeModuleResolver/utils.ts create mode 100644 web-infras/bundler/src/chunkGraph/type.ts create mode 100644 web-infras/bundler/src/config.ts create mode 100644 web-infras/bundler/src/depGraph/index.ts create mode 100644 web-infras/bundler/src/dev.ts create mode 100644 web-infras/bundler/src/utils/importVisitor.ts create mode 100644 web-infras/bundler/src/utils/removeImportVisitor.ts create mode 100644 web-infras/bundler/src/utils/resolvePath.ts create mode 100644 web-infras/bundler/tsconfig.build.json create mode 100644 web-infras/bundler/tsconfig.json create mode 100644 web-infras/generator/rollup.config.js create mode 100644 web-infras/generator/src/generator.ts create mode 100644 web-infras/generator/src/js/pattern.ts create mode 100644 web-infras/generator/tsconfig.build.json diff --git a/.gitignore b/.gitignore index 2c2c0c03..39610f55 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ node_modules !.yarn/sdks !.yarn/versions ## for some test file start -test.* \ No newline at end of file +test.* +## for build file +**/dist/* \ No newline at end of file diff --git a/package.json b/package.json index 1400bd51..45336a5d 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "private": true, "workspaces": [ - "web-infras/parser", "web-infras/common", + "web-infras/parser", "web-infras/generator", + "web-infras/bundler", "web-infras/analyzer", "website/frontend" ], diff --git a/web-infras/bundler/.gitignore b/web-infras/bundler/.gitignore new file mode 100644 index 00000000..77a44e29 --- /dev/null +++ b/web-infras/bundler/.gitignore @@ -0,0 +1,2 @@ +## Dev dir +dev/** \ No newline at end of file diff --git a/web-infras/bundler/.prettierignore b/web-infras/bundler/.prettierignore new file mode 100644 index 00000000..3764802a --- /dev/null +++ b/web-infras/bundler/.prettierignore @@ -0,0 +1,6 @@ +## tsconfig +**/tsconfig.json +## rollup config +**/rollup.config.js +## README +**/README.md diff --git a/web-infras/bundler/.prettierrc.json b/web-infras/bundler/.prettierrc.json new file mode 100644 index 00000000..57a55915 --- /dev/null +++ b/web-infras/bundler/.prettierrc.json @@ -0,0 +1,21 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "experimentalTernaries": false, + "singleQuote": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "all", + "singleAttributePerLine": false, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "insertPragma": false, + "printWidth": 110, + "requirePragma": false, + "tabWidth": 2, + "useTabs": false, + "embeddedLanguageFormatting": "auto" +} diff --git a/web-infras/bundler/README.md b/web-infras/bundler/README.md new file mode 100644 index 00000000..0d8b5cf4 --- /dev/null +++ b/web-infras/bundler/README.md @@ -0,0 +1,2 @@ +# Web Infra Bundler +WIP JS bundler. \ No newline at end of file diff --git a/web-infras/bundler/eslint.config.mjs b/web-infras/bundler/eslint.config.mjs new file mode 100644 index 00000000..728c7a6c --- /dev/null +++ b/web-infras/bundler/eslint.config.mjs @@ -0,0 +1,27 @@ +// @ts-check +import eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { + ignores: ["**/rollup.config.js", "**/dist/"], + }, + eslint.configs.recommended, + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + }, + }, +); diff --git a/web-infras/bundler/package.json b/web-infras/bundler/package.json new file mode 100644 index 00000000..ffc3f41a --- /dev/null +++ b/web-infras/bundler/package.json @@ -0,0 +1,44 @@ +{ + "name": "web-infra-bundler", + "packageManager": "yarn@3.6.3", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "scripts": { + "build": "rollup --config --bundleConfigAsCjs rollup.config.js", + "dev": "ts-node --swc ./src/dev.ts", + "format": "yarn prettier . --check", + "format:write": "yarn prettier . --write", + "lint": "yarn eslint", + "lint:fix": "yarn eslint --fix" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@rollup/plugin-typescript": "^11.1.5", + "@swc/core": "^1.7.10", + "@types/eslint": "^9", + "@types/eslint__js": "^8.42.3", + "chalk": "4.1.2", + "eslint": "^9.14.0", + "nodemon": "^3.0.1", + "prettier": "^3.3.2", + "rollup": "^4.1.4", + "rollup-plugin-dts": "^6.1.0", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "tslib": "^2.6.2", + "typescript": "^5.6.3", + "typescript-eslint": "^8.13.0", + "web-infra-common": "workspace:*", + "web-infra-generator": "workspace:*", + "web-infra-parser": "workspace:*" + }, + "lint-staged": { + "*.{ts}": [ + "yarn format:write", + "yarn lint:fix" + ], + "*.md": [ + "yarn format:write" + ] + } +} diff --git a/web-infras/bundler/rollup.config.js b/web-infras/bundler/rollup.config.js new file mode 100644 index 00000000..e31e1d95 --- /dev/null +++ b/web-infras/bundler/rollup.config.js @@ -0,0 +1,32 @@ +import typescriptPlugin from "@rollup/plugin-typescript"; +import { dts as typescriptTypePlugin } from "rollup-plugin-dts"; +import path from "path"; + +/** @type {import('rollup').RollupOptions} */ +export default [ + { + input: 'src/index.ts', + output: { + file: './dist/index.js', + format: 'cjs' + }, + plugins: [ + typescriptPlugin({ + tsconfig: path.join(__dirname, "tsconfig.build.json"), + }), + ] + }, + { + input: 'src/index.ts', + output: { + file: './dist/index.d.ts', + format: 'es' + }, + plugins: [ + typescriptPlugin({ + tsconfig: path.join(__dirname, "tsconfig.build.json"), + }), + typescriptTypePlugin() + ] + } +]; \ No newline at end of file diff --git a/web-infras/bundler/src/chunkGraph/index.ts b/web-infras/bundler/src/chunkGraph/index.ts new file mode 100644 index 00000000..2061e8ed --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/index.ts @@ -0,0 +1,52 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import type { BundlerConfig } from "@/src/config"; +import { DepGraph, ModuleId } from "@/src/depGraph"; +import { resolvePath } from "@/src/utils/resolvePath"; +import type { Chunk } from "@/src/chunkGraph/type"; +import { renderRuntimeModuleTemplate, runtimeModulize } from "@/src/chunkGraph/runtimeModuleResolver"; +/** + * + * @param entry + * @param graph + * @returns + */ +function getReverseDFSOrdering(entry: ModuleId, graph: DepGraph): ModuleId[] { + const orders: ModuleId[] = []; + const mark: Record = {}; + function dfsVisit(current: ModuleId) { + if (mark[current] === true) return; + const deps = graph.moduleMap[current].importer; + mark[current] = true; + for (const dep of deps) { + dfsVisit(dep); + } + orders.push(current); + } + dfsVisit(entry); + return orders; +} + +export function buildChunks(graph: DepGraph, config: BundlerConfig): Chunk[] { + const configs = [config]; + const chunks: Array = []; + for (const config of configs) { + const entryAbsolutPath = resolvePath(config.entry, process.cwd()); + const reverseTopoOrders = getReverseDFSOrdering(entryAbsolutPath, graph); + chunks.push({ + moduleIds: reverseTopoOrders, + }); + } + return chunks; +} + +export async function renderChunks(config: BundlerConfig, chunks: Chunk[], graph: DepGraph) { + let index = 0; + for (const chunk of chunks) { + runtimeModulize(chunk, graph); + const code = renderRuntimeModuleTemplate(config.entry, chunk, graph); + const outputAbsolutePath = path.resolve(resolvePath(config.output, process.cwd()), `output_${index}.js`); + await fs.writeFile(outputAbsolutePath, code); + index++; + } +} diff --git a/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/const.ts b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/const.ts new file mode 100644 index 00000000..f42012a5 --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/const.ts @@ -0,0 +1,19 @@ +import { createSourcePosition } from "web-infra-common"; + +export const DUMMY_SOURCE_POSITION = createSourcePosition(); +export const RUNTIME_MODULE_IMPORT_CALLEE = "_runtime_module_import"; +export const RUNTIME_MODULE_EXPORT_REF = "_runtime_module_export"; +export const RUNTIME_MODULE_MAP = "_runtime_module_map"; +export const RUNTIME_MODULE_CACHE = "_runtime_module_cache"; +export const RUNTIME_MODULE_BOOTSTRAP_TEMPLATE = ` +var ${RUNTIME_MODULE_CACHE} = {}; +var ${RUNTIME_MODULE_IMPORT_CALLEE} = (source) => { + const runtimeCache = ${RUNTIME_MODULE_CACHE}[source]; + if(runtimeCache) { + return runtimeCache; + } + const ${RUNTIME_MODULE_EXPORT_REF} = {} + ${RUNTIME_MODULE_MAP}[source](${RUNTIME_MODULE_IMPORT_CALLEE}, ${RUNTIME_MODULE_EXPORT_REF}); + ${RUNTIME_MODULE_CACHE}[source] = ${RUNTIME_MODULE_EXPORT_REF}; + return ${RUNTIME_MODULE_EXPORT_REF}; +}`; diff --git a/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/exportDeclarationTransformer.ts b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/exportDeclarationTransformer.ts new file mode 100644 index 00000000..851ef34b --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/exportDeclarationTransformer.ts @@ -0,0 +1,314 @@ +import { ModuleId } from "@/src/depGraph"; +import { RUNTIME_MODULE_EXPORT_REF, RUNTIME_MODULE_IMPORT_CALLEE, DUMMY_SOURCE_POSITION } from "./const"; +import { moduleSourceToModuleId } from "./utils"; +import { + Identifier, + Expression, + Factory, + SyntaxKinds, + ExportDefaultDeclaration, + ClassExpression, + FunctionExpression, + ExportNamedDeclarations, + ExpressionStatement, + ExportAllDeclaration, + isStringLiteral, + Program, + ModuleItem, +} from "web-infra-common"; + +/** + * Helper to create `_runtime_module_export. = ` to replace export. + * @returns + */ +function createRuntimeModuleExportAssignment(rhs: Identifier, id: Expression) { + return Factory.createExpressionStatement( + Factory.createAssignmentExpression( + Factory.createMemberExpression( + false, + Factory.createIdentifier( + RUNTIME_MODULE_EXPORT_REF, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + rhs, + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + id, + SyntaxKinds.AssginOperator, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); +} +function handleDefaultExportDeclaration(node: ExportDefaultDeclaration) { + switch (node.declaration.kind) { + case SyntaxKinds.ClassDeclaration: { + if (node.declaration.id) { + return { + nextItem: node.declaration, + runtimeExport: createRuntimeModuleExportAssignment( + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + node.declaration.id, + ), + }; + } else { + const classExpr: ClassExpression = { + ...node.declaration, + kind: SyntaxKinds.ClassExpression, + }; + return { + nextItem: undefined, + runtimeExport: createRuntimeModuleExportAssignment( + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + classExpr, + ), + }; + } + } + case SyntaxKinds.FunctionDeclaration: { + const functionExpr: FunctionExpression = { + ...node.declaration, + kind: SyntaxKinds.FunctionExpression, + }; + if (functionExpr.name) { + return { + nextItem: node.declaration, + runtimeExport: createRuntimeModuleExportAssignment( + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + node.declaration.name, + ), + }; + } else { + return { + nextItem: undefined, + runtimeExport: createRuntimeModuleExportAssignment( + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + functionExpr, + ), + }; + } + } + case SyntaxKinds.TSTypeAliasDeclaration: + case SyntaxKinds.TSInterfaceDeclaration: + case SyntaxKinds.TSEnumDeclaration: + case SyntaxKinds.TSDeclareFunction: { + throw new Error(); + } + default: { + return { + nextItem: undefined, + runtimeExport: createRuntimeModuleExportAssignment( + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + node.declaration, + ), + }; + } + } +} + +function handleExportNameDeclaration(node: ExportNamedDeclarations) { + if (node.declaration) { + switch (node.declaration.kind) { + case SyntaxKinds.VariableDeclaration: { + // not implement yet. + throw new Error(); + } + case SyntaxKinds.FunctionDeclaration: { + return { + nextItem: node.declaration, + runtimeExport: createRuntimeModuleExportAssignment(node.declaration.name, node.declaration.name), + }; + } + case SyntaxKinds.ClassDeclaration: { + const name = node.declaration.id!; + return { + nextItem: node.declaration, + runtimeExport: createRuntimeModuleExportAssignment(name, name), + }; + } + default: { + // unreach + throw new Error(); + } + } + } else if (node.source) { + // not implement yet. + throw new Error(); + } + const runtimeExports: ExpressionStatement[] = []; + for (const specifier of node.specifiers) { + runtimeExports.push( + createRuntimeModuleExportAssignment( + (specifier.local ? specifier.local : specifier.exported) as Identifier, + specifier.exported, + ), + ); + } + return { + nextItem: undefined, + runtimeExport: runtimeExports, + }; +} + +function handleExportAllDeclaration(node: ExportAllDeclaration, moduleIds: ModuleId[]) { + const runtimeModuleImport = Factory.createCallExpression( + Factory.createIdentifier( + RUNTIME_MODULE_IMPORT_CALLEE, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + [ + Factory.createStringLiteral( + moduleSourceToModuleId(node.source.value, moduleIds), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ], + undefined, + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); + if (node.exported) { + if (isStringLiteral(node.exported)) { + // TODO + throw new Error(); + } + /** + * ``` + * export * as React from "./some" + * ``` + * ``` + * _runtime_module_export.React = _runtime_module_import("./some"); + * ``` + */ + return { + nextItem: undefined, + runtimeExport: createRuntimeModuleExportAssignment(node.exported, runtimeModuleImport), + }; + } else { + return { + nextItem: undefined, + /** + * ``` + * export * from "./some" + * ``` + * ``` + * _runtime_module_export = { + * ..._runtime_module_export, + * ..._runtime_module_import("./some") + * } + * ``` + */ + runtimeExport: Factory.createAssignmentExpression( + Factory.createIdentifier( + RUNTIME_MODULE_EXPORT_REF, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + Factory.createObjectExpression( + [ + Factory.createSpreadElement( + Factory.createIdentifier( + RUNTIME_MODULE_EXPORT_REF, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + Factory.createSpreadElement(runtimeModuleImport, DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION), + ], + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + SyntaxKinds.AssginOperator, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + }; + } +} + +export function exportDeclarationTransformer(program: Program, moduleIds: ModuleId[]) { + const nextBody: ModuleItem[] = []; + const runtimeModulePolyfill: ModuleItem[] = []; + for (const item of program.body) { + switch (item.kind) { + case SyntaxKinds.ExportDefaultDeclaration: { + const defaultExport = item as ExportDefaultDeclaration; + const { nextItem, runtimeExport } = handleDefaultExportDeclaration(defaultExport); + if (nextItem) { + nextBody.push(nextItem); + } + runtimeModulePolyfill.push(runtimeExport); + break; + } + case SyntaxKinds.ExportAllDeclaration: { + const allExport = item as ExportAllDeclaration; + const { runtimeExport } = handleExportAllDeclaration(allExport, moduleIds); + runtimeModulePolyfill.push(runtimeExport); + break; + } + case SyntaxKinds.ExportNamedDeclaration: { + const namedExport = item as ExportNamedDeclarations; + const { nextItem, runtimeExport } = handleExportNameDeclaration(namedExport); + if (nextItem) { + nextBody.push(nextItem); + } + runtimeModulePolyfill.push(...(Array.isArray(runtimeExport) ? runtimeExport : [runtimeExport])); + break; + } + default: { + nextBody.push(item); + break; + } + } + } + program.body = [...nextBody, ...runtimeModulePolyfill]; + return; +} diff --git a/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/importDeclarationTransformer.ts b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/importDeclarationTransformer.ts new file mode 100644 index 00000000..2d8e9561 --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/importDeclarationTransformer.ts @@ -0,0 +1,147 @@ +import { ModuleId } from "@/src/depGraph"; +import { moduleSourceToModuleId } from "./utils"; +import { + createSourcePosition, + Factory, + ImportDeclaration, + isStringLiteral, + ModuleItem, + ObjectPattern, + Program, + SyntaxKinds, + VariableDeclarator, +} from "web-infra-common"; + +const DUMMY_SOURCE_POSITION = createSourcePosition(); +const RUNTIME_MODULE_IMPORT_CALLEE = "_runtime_module_import"; + +function handleImportDeclararation(node: ImportDeclaration, moduleIds: ModuleId[]) { + const declarators: VariableDeclarator[] = []; + function createRuntimeModuleCallExpression() { + return Factory.createCallExpression( + Factory.createIdentifier( + RUNTIME_MODULE_IMPORT_CALLEE, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + [ + Factory.createStringLiteral( + moduleSourceToModuleId(node.source.value, moduleIds), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ], + undefined, + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); + } + let destructurePattern: ObjectPattern | null = null; + function getDestructurePattern() { + if (destructurePattern === null) { + destructurePattern = Factory.createObjectPattern( + [], + undefined, + undefined, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); + } + return destructurePattern; + } + for (const specifier of node.specifiers) { + switch (specifier.kind) { + case SyntaxKinds.ImportSpecifier: { + const imported = isStringLiteral(specifier.imported) + ? Factory.createIdentifier( + specifier.imported.value, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ) + : specifier.imported; + getDestructurePattern().properties.push( + Factory.createObjectPatternProperty( + imported, + specifier.local ?? undefined, + false, + specifier.local === null, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ); + break; + } + case SyntaxKinds.ImportNamespaceSpecifier: { + const name = specifier.imported; + if (isStringLiteral(name)) { + throw new Error(); + } + declarators.push( + Factory.createVariableDeclarator( + name, + createRuntimeModuleCallExpression(), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ); + break; + } + case SyntaxKinds.ImportDefaultSpecifier: { + const name = specifier.imported; + const memberExpression = Factory.createMemberExpression( + false, + createRuntimeModuleCallExpression(), + Factory.createIdentifier( + "default", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); + declarators.push( + Factory.createVariableDeclarator( + name, + memberExpression, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ); + break; + } + } + } + if (destructurePattern) { + declarators.push( + Factory.createVariableDeclarator( + destructurePattern, + createRuntimeModuleCallExpression(), + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ); + } + return Factory.createVariableDeclaration(declarators, "var", DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION); +} + +export function importDeclarationTransformer(program: Program, moduleIds: ModuleId[]) { + const nextBody: ModuleItem[] = []; + for (const item of program.body) { + if (item.kind === SyntaxKinds.ImportDeclaration) { + const variableDeclar = handleImportDeclararation(item as ImportDeclaration, moduleIds); + nextBody.push(variableDeclar); + continue; + } + nextBody.push(item); + } + program.body = nextBody; + return; +} diff --git a/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/index.ts b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/index.ts new file mode 100644 index 00000000..108daf49 --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/index.ts @@ -0,0 +1,110 @@ +/** + * When bundling multiple module into a chunk, we need to concate multiple + * module where are import each other with a graph relation, and import and + * export need to be solve (replace or flating) into a single chunk. + * + * There we concate the modules by wrap each module into a function, lower the + * module scope into function scope and using a runtime polyfill to replace + * import and export syntax in module, if you familier with webpack, it actually + * is same way webpack handle module export and import. + */ +import { Factory, StatementListItem } from "web-infra-common"; +import { generate } from "web-infra-generator"; +import { Chunk } from "@/src/chunkGraph/type"; +import { DepGraph, ModuleId } from "@/src/depGraph"; +import { exportDeclarationTransformer } from "./exportDeclarationTransformer"; +import { importDeclarationTransformer } from "./importDeclarationTransformer"; +import { moduleSourceToModuleId } from "./utils"; +import { + DUMMY_SOURCE_POSITION, + RUNTIME_MODULE_EXPORT_REF, + RUNTIME_MODULE_IMPORT_CALLEE, + RUNTIME_MODULE_MAP, + RUNTIME_MODULE_BOOTSTRAP_TEMPLATE, +} from "./const"; + +function createRuntimeModule(body: StatementListItem[]) { + return Factory.createArrowExpression( + false, + Factory.createFunctionBody(body, DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION), + [ + Factory.createIdentifier( + RUNTIME_MODULE_IMPORT_CALLEE, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + Factory.createIdentifier( + RUNTIME_MODULE_EXPORT_REF, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + ], + undefined, + undefined, + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); +} + +function createRuntimeModuleMap(moduleMap: Record) { + const map = Factory.createObjectExpression([], false, DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION); + for (const [id, body] of Object.entries(moduleMap)) { + map.properties.push( + Factory.createObjectProperty( + Factory.createStringLiteral(id, DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION), + createRuntimeModule(body), + false, + false, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ); + } + return Factory.createVariableDeclaration( + [ + Factory.createVariableDeclarator( + Factory.createIdentifier( + RUNTIME_MODULE_MAP, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + undefined, + undefined, + ), + map, + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ), + ], + "var", + DUMMY_SOURCE_POSITION, + DUMMY_SOURCE_POSITION, + ); +} + +export function renderRuntimeModuleTemplate(entry: string, chunk: Chunk, depGraph: DepGraph) { + const moduleRecord = chunk.moduleIds.reduce( + (record, id) => { + record[id] = depGraph.moduleMap[id].ast.body as StatementListItem[]; + return record; + }, + {} as Record, + ); + const moduleMapObjectExpressionStatement = createRuntimeModuleMap(moduleRecord); + const mapCode = generate( + Factory.createProgram([moduleMapObjectExpressionStatement], DUMMY_SOURCE_POSITION, DUMMY_SOURCE_POSITION), + ); + return `${mapCode}\n${RUNTIME_MODULE_BOOTSTRAP_TEMPLATE}\n${RUNTIME_MODULE_IMPORT_CALLEE}("${moduleSourceToModuleId(entry, chunk.moduleIds)}")`; +} + +export function runtimeModulize(chunk: Chunk, depGraph: DepGraph) { + for (const moduleId of chunk.moduleIds) { + const program = depGraph.moduleMap[moduleId].ast; + importDeclarationTransformer(program, chunk.moduleIds); + exportDeclarationTransformer(program, chunk.moduleIds); + } +} diff --git a/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/utils.ts b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/utils.ts new file mode 100644 index 00000000..6dfe8864 --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/runtimeModuleResolver/utils.ts @@ -0,0 +1,17 @@ +import { ModuleId } from "@/src/depGraph"; + +export function moduleSourceToModuleId(source: string, moduleIds: ModuleId[]) { + for (const id of moduleIds) { + if (source.startsWith("./")) { + if (id.endsWith(source.slice(2))) { + return id; + } + } else { + if (id === source) { + return id; + } + } + } + // unreach; + throw new Error(); +} diff --git a/web-infras/bundler/src/chunkGraph/type.ts b/web-infras/bundler/src/chunkGraph/type.ts new file mode 100644 index 00000000..447feae8 --- /dev/null +++ b/web-infras/bundler/src/chunkGraph/type.ts @@ -0,0 +1,4 @@ +import { ModuleId } from "@/src/depGraph/index"; +export interface Chunk { + moduleIds: ModuleId[]; +} diff --git a/web-infras/bundler/src/config.ts b/web-infras/bundler/src/config.ts new file mode 100644 index 00000000..f7124206 --- /dev/null +++ b/web-infras/bundler/src/config.ts @@ -0,0 +1,4 @@ +export interface BundlerConfig { + entry: string; + output: string; +} diff --git a/web-infras/bundler/src/depGraph/index.ts b/web-infras/bundler/src/depGraph/index.ts new file mode 100644 index 00000000..cfad5801 --- /dev/null +++ b/web-infras/bundler/src/depGraph/index.ts @@ -0,0 +1,48 @@ +import { readFile } from "fs/promises"; +import { BundlerConfig } from "@/src/config"; +import { Program } from "web-infra-common"; +import { parse } from "web-infra-parser"; +import { getImporterSource } from "../utils/importVisitor"; +import { resolvePath, AbsolutePath } from "@/src/utils/resolvePath"; + +export type ModuleId = AbsolutePath; + +export interface Module { + // absolute path of module + id: ModuleId; + // JS ast + ast: Program; + // all the file this module import + importer: AbsolutePath[]; +} + +export interface DepGraph { + moduleMap: { [key: ModuleId]: Module }; +} + +function createModule(id: string, ast: Program, importer: AbsolutePath[]): Module { + return { id, ast, importer }; +} +export async function createGraph(config: BundlerConfig): Promise { + const entryAbsolutPath = resolvePath(config.entry, process.cwd()); + const queue: Array = [entryAbsolutPath]; + const graph: DepGraph = { + moduleMap: {}, + }; + while (queue.length > 0) { + const modAbsolutePath = queue.pop()!; + if (graph.moduleMap[modAbsolutePath]) { + continue; + } + const fileString = (await readFile(modAbsolutePath)).toString(); + const ast = parse(fileString, { sourceType: "module" }); + const importerSystemPaths = getImporterSource(ast); + const modDirabsolutePath = modAbsolutePath.split("/").slice(0, -1).join("/"); + const importerAbsolutePaths = importerSystemPaths.map((importerSystemPath) => + resolvePath(importerSystemPath, modDirabsolutePath), + ); + graph.moduleMap[modAbsolutePath] = createModule(modAbsolutePath, ast, importerAbsolutePaths); + queue.push(...importerAbsolutePaths); + } + return graph; +} diff --git a/web-infras/bundler/src/dev.ts b/web-infras/bundler/src/dev.ts new file mode 100644 index 00000000..02fd6236 --- /dev/null +++ b/web-infras/bundler/src/dev.ts @@ -0,0 +1,15 @@ +import { createGraph } from "@/src/depGraph"; +import { buildChunks, renderChunks } from "@/src/chunkGraph"; + +async function main() { + const config = { + entry: "./dev/src/index.js", + output: "./dev/dist", + }; + const depGraph = await createGraph(config); + console.log(depGraph); + const chunks = buildChunks(depGraph, config); + await renderChunks(config, chunks, depGraph); +} + +main(); diff --git a/web-infras/bundler/src/utils/importVisitor.ts b/web-infras/bundler/src/utils/importVisitor.ts new file mode 100644 index 00000000..f62e7fe4 --- /dev/null +++ b/web-infras/bundler/src/utils/importVisitor.ts @@ -0,0 +1,15 @@ +import { Visitor, visitNode, SyntaxKinds, Program } from "web-infra-common"; + +/** + * Get all the dep(importer) of current module + */ +export function getImporterSource(program: Program) { + const sources: string[] = []; + const importerVisitorTable: Visitor = { + [SyntaxKinds.ImportDeclaration]: (node, _) => { + sources.push(node.source.value); + }, + }; + visitNode(program, importerVisitorTable); + return sources; +} diff --git a/web-infras/bundler/src/utils/removeImportVisitor.ts b/web-infras/bundler/src/utils/removeImportVisitor.ts new file mode 100644 index 00000000..a86e8df7 --- /dev/null +++ b/web-infras/bundler/src/utils/removeImportVisitor.ts @@ -0,0 +1,64 @@ +import { + Visitor, + visitNode, + SyntaxKinds, + Program, + ModuleItem, + ExportDefaultDeclaration, + ExportNamedDeclarations, +} from "web-infra-common"; + +/** + * Remove All the import declaration of program + */ +export function removeAllImportDeclaration(program: Program) { + const removeImportDeclarationTable: Visitor = { + [SyntaxKinds.Program]: (node, _) => { + const nextBody = []; + for (const item of node.body) { + if (item.kind === SyntaxKinds.ImportDeclaration) { + continue; + } + nextBody.push(item); + } + node.body = nextBody; + }, + }; + visitNode(program, removeImportDeclarationTable); + return; +} + +export function removeModuleRelativeItem(program: Program) { + const visitor: Visitor = { + [SyntaxKinds.Program]: (node, _) => { + const nextBody: ModuleItem[] = []; + for (const item of node.body) { + switch (item.kind) { + case SyntaxKinds.ImportDeclaration: { + continue; + } + case SyntaxKinds.ExportAllDeclaration: { + continue; + } + case SyntaxKinds.ExportDefaultDeclaration: { + const defaultItem = item as ExportDefaultDeclaration; + nextBody.push(defaultItem.declaration); + continue; + } + case SyntaxKinds.ExportNamedDeclaration: { + const nameDeclarItem = item as ExportNamedDeclarations; + if (nameDeclarItem.declaration) { + nextBody.push(nameDeclarItem.declaration); + continue; + } + } + } + nextBody.push(item); + continue; + } + node.body = nextBody; + }, + }; + visitNode(program, visitor); + return; +} diff --git a/web-infras/bundler/src/utils/resolvePath.ts b/web-infras/bundler/src/utils/resolvePath.ts new file mode 100644 index 00000000..8bad5f91 --- /dev/null +++ b/web-infras/bundler/src/utils/resolvePath.ts @@ -0,0 +1,12 @@ +import path from "node:path"; + +export type AbsolutePath = string; +// type RelativePath = string; +export type SystemPath = string; + +export function resolvePath(pth: SystemPath, currentModDirPath: AbsolutePath): AbsolutePath { + if (pth.startsWith("./")) { + return path.resolve(currentModDirPath, pth); + } + return pth; +} diff --git a/web-infras/bundler/tsconfig.build.json b/web-infras/bundler/tsconfig.build.json new file mode 100644 index 00000000..bfd73f64 --- /dev/null +++ b/web-infras/bundler/tsconfig.build.json @@ -0,0 +1,114 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ESNext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, + "paths": { + "@/src/*": ["src/*"] + } /* Specify a set of entries that re-map imports to additional lookup locations. */, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} diff --git a/web-infras/bundler/tsconfig.json b/web-infras/bundler/tsconfig.json new file mode 100644 index 00000000..b8f9d1d7 --- /dev/null +++ b/web-infras/bundler/tsconfig.json @@ -0,0 +1,115 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "CommonJS", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@/src/*": ["src/*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} + \ No newline at end of file diff --git a/web-infras/generator/eslint.config.mjs b/web-infras/generator/eslint.config.mjs index 8e2b8991..728c7a6c 100644 --- a/web-infras/generator/eslint.config.mjs +++ b/web-infras/generator/eslint.config.mjs @@ -1,21 +1,27 @@ // @ts-check - import eslint from "@eslint/js"; import tseslint from "typescript-eslint"; -export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, { - rules: { - "@typescript-eslint/no-unused-vars": [ - "error", - { - args: "all", - argsIgnorePattern: "^_", - caughtErrors: "all", - caughtErrorsIgnorePattern: "^_", - destructuredArrayIgnorePattern: "^_", - varsIgnorePattern: "^_", - ignoreRestSiblings: true, - }, - ], +export default tseslint.config( + { + ignores: ["**/rollup.config.js", "**/dist/"], + }, + eslint.configs.recommended, + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + }, }, -}); +); diff --git a/web-infras/generator/package.json b/web-infras/generator/package.json index ac9e7206..7a4abac8 100644 --- a/web-infras/generator/package.json +++ b/web-infras/generator/package.json @@ -1,8 +1,10 @@ { "name": "web-infra-generator", "packageManager": "yarn@3.6.3", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "scripts": { - "build": "rollup --config --bundleConfigAsCjs rollup.config.js", + "build": "rollup --config --bundleConfigAsCjs rollup.config.js", "dev": "ts-node --swc ./src/dev.ts", "format": "yarn prettier . --check", "format:write": "yarn prettier . --write", diff --git a/web-infras/generator/rollup.config.js b/web-infras/generator/rollup.config.js new file mode 100644 index 00000000..e31e1d95 --- /dev/null +++ b/web-infras/generator/rollup.config.js @@ -0,0 +1,32 @@ +import typescriptPlugin from "@rollup/plugin-typescript"; +import { dts as typescriptTypePlugin } from "rollup-plugin-dts"; +import path from "path"; + +/** @type {import('rollup').RollupOptions} */ +export default [ + { + input: 'src/index.ts', + output: { + file: './dist/index.js', + format: 'cjs' + }, + plugins: [ + typescriptPlugin({ + tsconfig: path.join(__dirname, "tsconfig.build.json"), + }), + ] + }, + { + input: 'src/index.ts', + output: { + file: './dist/index.d.ts', + format: 'es' + }, + plugins: [ + typescriptPlugin({ + tsconfig: path.join(__dirname, "tsconfig.build.json"), + }), + typescriptTypePlugin() + ] + } +]; \ No newline at end of file diff --git a/web-infras/generator/src/dev.ts b/web-infras/generator/src/dev.ts index 5c0db65e..965bdcae 100644 --- a/web-infras/generator/src/dev.ts +++ b/web-infras/generator/src/dev.ts @@ -1,7 +1,7 @@ import { parse } from "web-infra-parser"; -import { Generaotr } from "@/src/index"; +import { Generator } from "@/src/generator"; const ast = parse("function a(c) { const cc = 10+c; return cc; }"); -const generator = new Generaotr(); +const generator = new Generator(); generator.genProgram(ast); diff --git a/web-infras/generator/src/generator.ts b/web-infras/generator/src/generator.ts new file mode 100644 index 00000000..a4ab2ce4 --- /dev/null +++ b/web-infras/generator/src/generator.ts @@ -0,0 +1,32 @@ +import * as HelperImpl from "./helper"; +import * as JSImpl from "./js"; + +export class Generator { + code: string; + spaceLevel: number; + constructor() { + this.code = ""; + this.spaceLevel = 0; + } +} + +type JSImplType = typeof JSImpl; +type HelperImpType = typeof HelperImpl; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function bindingParserMethod(methods: any) { + Object.entries(methods).forEach(([name, method]) => { + // @ts-expect-error implement in JS prototype + Generator.prototype[name] = method; + }); +} + +bindingParserMethod(HelperImpl); +bindingParserMethod(JSImpl); + +declare module "./generator" { + interface Generator extends JSImplType, HelperImpType { + code: string; + spaceLevel: number; + } +} diff --git a/web-infras/generator/src/helper.ts b/web-infras/generator/src/helper.ts index 0cb39359..6767aeb5 100644 --- a/web-infras/generator/src/helper.ts +++ b/web-infras/generator/src/helper.ts @@ -1,12 +1,12 @@ import { SyntaxKinds, SytaxKindsMapLexicalLiteral } from "web-infra-common"; -import { Generaotr } from "@/src/index"; +import { Generator } from "@/src/generator"; /** * Write a syntax token, token kind can not be * - AST node * - Literal * - Comment */ -export function writeToken(this: Generaotr, tokenKind: SyntaxKinds) { +export function writeToken(this: Generator, tokenKind: SyntaxKinds) { if (tokenKind > 10107) { throw new Error(); } @@ -17,7 +17,7 @@ export function writeToken(this: Generaotr, tokenKind: SyntaxKinds) { /** * Write a space in current level, one level is 2 space. */ -export function writePrefixSpace(this: Generaotr) { +export function writePrefixSpace(this: Generator) { for (let i = 0; i < this.spaceLevel * 2; ++i) { this.code += " "; } @@ -25,25 +25,25 @@ export function writePrefixSpace(this: Generaotr) { /** * Write a line terminator. */ -export function writeLineTerminator(this: Generaotr) { +export function writeLineTerminator(this: Generator) { this.code += "\n"; } /** * Enter another space for print. */ -export function enterSpaceBlock(this: Generaotr) { +export function enterSpaceBlock(this: Generator) { this.spaceLevel++; } /** * Exit space scope. */ -export function exitSpaceBlock(this: Generaotr) { +export function exitSpaceBlock(this: Generator) { this.spaceLevel--; } /** * Write something with `()` paran. */ -export function writeWithParan(this: Generaotr, callback: () => void) { +export function writeWithParan(this: Generator, callback: () => void) { this.writeToken(SyntaxKinds.ParenthesesLeftPunctuator); callback(); this.writeToken(SyntaxKinds.ParenthesesRightPunctuator); @@ -52,23 +52,28 @@ export function writeWithParan(this: Generaotr, callback: () => void) { * Write something with `{}` wrapper. * - changeline: add line terminator after `{`. */ -export function writeWithBraces(this: Generaotr, changeLine: boolean, callback: () => void) { +export function writeWithBraces(this: Generator, changeLine: boolean, callback: () => void) { this.writeToken(SyntaxKinds.BracesLeftPunctuator); - if (changeLine) this.writeLineTerminator(); + if (changeLine) { + this.writeLineTerminator(); + } this.enterSpaceBlock(); callback(); this.exitSpaceBlock(); + if (changeLine) { + this.writePrefixSpace(); + } this.writeToken(SyntaxKinds.BracesRightPunctuator); } /** * Write a contextual keyword, basicly mean anything. */ -export function writeRawString(this: Generaotr, keyword: string) { +export function writeRawString(this: Generator, keyword: string) { this.code += keyword; } /** * Write a space. */ -export function writeSpace(this: Generaotr) { +export function writeSpace(this: Generator) { this.code += " "; } diff --git a/web-infras/generator/src/index.ts b/web-infras/generator/src/index.ts index bc3f5744..e32487bf 100644 --- a/web-infras/generator/src/index.ts +++ b/web-infras/generator/src/index.ts @@ -1,29 +1,8 @@ -import * as HelperImpl from "./helper"; -import * as JSImpl from "./js"; +import { Program } from "web-infra-common"; +import { Generator } from "./generator"; -export class Generaotr { - code: string; - spaceLevel: number; - constructor() { - this.code = ""; - this.spaceLevel = 0; - } -} - -type JSImplType = typeof JSImpl; -type HelperImpType = typeof HelperImpl; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function bindingParserMethod(methods: any) { - Object.entries(methods).forEach(([name, method]) => { - // @ts-expect-error implement in JS prototype - Generaotr.prototype[name] = method; - }); -} - -bindingParserMethod(HelperImpl); -bindingParserMethod(JSImpl); - -declare module "./index" { - interface Generaotr extends JSImplType, HelperImpType {} +export function generate(program: Program) { + const generator = new Generator(); + generator.genProgram(program); + return generator.code; } diff --git a/web-infras/generator/src/js/declaration.ts b/web-infras/generator/src/js/declaration.ts index 191b9242..12d6edb0 100644 --- a/web-infras/generator/src/js/declaration.ts +++ b/web-infras/generator/src/js/declaration.ts @@ -1,4 +1,4 @@ -import { Generaotr } from "@/src/index"; +import { Generator } from "@/src/generator"; import { SyntaxKinds, Pattern, @@ -8,7 +8,7 @@ import { VariableDeclarator, } from "web-infra-common"; -export function genVariableDeclaration(this: Generaotr, variableDeclaration: VariableDeclaration) { +export function genVariableDeclaration(this: Generator, variableDeclaration: VariableDeclaration) { this.writeRawString(variableDeclaration.variant); this.writeSpace(); this.genVariableDeclarator(variableDeclaration.declarations[0]); @@ -19,7 +19,7 @@ export function genVariableDeclaration(this: Generaotr, variableDeclaration: Var this.writeToken(SyntaxKinds.SemiPunctuator); this.writeLineTerminator(); } -export function genVariableDeclarator(this: Generaotr, declarator: VariableDeclarator) { +export function genVariableDeclarator(this: Generator, declarator: VariableDeclarator) { this.genModuleItem(declarator.id); if (declarator.init) { this.writeSpace(); @@ -28,7 +28,7 @@ export function genVariableDeclarator(this: Generaotr, declarator: VariableDecla this.genModuleItem(declarator.init); } } -export function genFunctionDeclaration(this: Generaotr, functionDeclar: FunctionDeclaration) { +export function genFunctionDeclaration(this: Generator, functionDeclar: FunctionDeclaration) { if (functionDeclar.async) { this.writeRawString("async"); this.writeSpace(); @@ -43,9 +43,10 @@ export function genFunctionDeclaration(this: Generaotr, functionDeclar: Function this.genFunctionParam(functionDeclar.params); this.writeSpace(); this.genFunctionBody(functionDeclar.body); + this.writeLineTerminator(); } -export function genFunctionParam(this: Generaotr, params: Pattern[]) { +export function genFunctionParam(this: Generator, params: Pattern[]) { this.writeWithParan(() => { params.forEach((param, index) => { this.genModuleItem(param); @@ -53,7 +54,7 @@ export function genFunctionParam(this: Generaotr, params: Pattern[]) { }); }); } -export function genFunctionBody(this: Generaotr, body: FunctionBody) { +export function genFunctionBody(this: Generator, body: FunctionBody) { this.writeWithBraces(true, () => { for (const statementItem of body.body) { this.writePrefixSpace(); diff --git a/web-infras/generator/src/js/expression.ts b/web-infras/generator/src/js/expression.ts index 3238614f..0c321463 100644 --- a/web-infras/generator/src/js/expression.ts +++ b/web-infras/generator/src/js/expression.ts @@ -1,4 +1,4 @@ -import { Generaotr } from "@/src/index"; +import { Generator } from "@/src/generator"; import { SyntaxKinds, Super, @@ -35,71 +35,73 @@ import { ArrorFunctionExpression, } from "web-infra-common"; -export function writeParanIfNeed(this: Generaotr, isParan: boolean | undefined, callback: () => void) { +export function writeParanIfNeed(this: Generator, isParan: boolean | undefined, callback: () => void) { if (isParan) { this.writeWithParan(callback); } else { callback(); } } -export function genSuper(this: Generaotr, superExpr: Super) { +export function genSuper(this: Generator, superExpr: Super) { this.writeParanIfNeed(superExpr.parentheses, () => { this.writeToken(SyntaxKinds.SuperKeyword); }); } -export function genImport(this: Generaotr, importExpr: Import) { +export function genImport(this: Generator, importExpr: Import) { this.writeParanIfNeed(importExpr.parentheses, () => { this.writeToken(SyntaxKinds.ImportKeyword); }); } -export function genThisExpression(this: Generaotr, thisExpr: ThisExpression) { +export function genThisExpression(this: Generator, thisExpr: ThisExpression) { this.writeParanIfNeed(thisExpr.parentheses, () => { this.writeToken(SyntaxKinds.ThisKeyword); }); } -export function genIdentifier(this: Generaotr, identifer: Identifier) { +export function genIdentifier(this: Generator, identifer: Identifier) { this.writeParanIfNeed(identifer.parentheses, () => { this.writeRawString(identifer.name); }); } -export function genPrivateName(this: Generaotr, privateName: PrivateName) { +export function genPrivateName(this: Generator, privateName: PrivateName) { this.writeParanIfNeed(privateName.parentheses, () => { this.writeToken(SyntaxKinds.HashTagPunctuator); this.writeRawString(privateName.name); }); } -export function genNumberLiteral(this: Generaotr, numberLiteral: NumberLiteral) { +export function genNumberLiteral(this: Generator, numberLiteral: NumberLiteral) { this.writeParanIfNeed(numberLiteral.parentheses, () => { this.writeRawString(numberLiteral.rawValue); }); } -export function genStringLiteral(this: Generaotr, stringLiteral: StringLiteral) { +export function genStringLiteral(this: Generator, stringLiteral: StringLiteral) { this.writeParanIfNeed(stringLiteral.parentheses, () => { + this.writeToken(SyntaxKinds.SingleQuotationPunctuator); this.writeRawString(stringLiteral.value); + this.writeToken(SyntaxKinds.SingleQuotationPunctuator); }); } -export function genBoolLiteral(this: Generaotr, boolLiteral: BoolLiteral) { +export function genBoolLiteral(this: Generator, boolLiteral: BoolLiteral) { this.writeParanIfNeed(boolLiteral.parentheses, () => { this.writeRawString(boolLiteral.value.toString()); }); } -export function genNullLiteral(this: Generaotr, nullLiteral: NullLiteral) { +export function genNullLiteral(this: Generator, nullLiteral: NullLiteral) { this.writeParanIfNeed(nullLiteral.parentheses, () => { this.writeToken(SyntaxKinds.NullKeyword); }); } -export function genUndefiniedLiteral(this: Generaotr, undefinbedLiteral: UndefinbedLiteral) { +export function genUndefiniedLiteral(this: Generator, undefinbedLiteral: UndefinbedLiteral) { this.writeParanIfNeed(undefinbedLiteral.parentheses, () => { this.writeToken(SyntaxKinds.UndefinedKeyword); }); } -export function genRegexLiteral(this: Generaotr, regexLiteral: RegexLiteral) { +export function genRegexLiteral(this: Generator, regexLiteral: RegexLiteral) { this.writeParanIfNeed(regexLiteral.parentheses, () => { this.writeRawString(`/${regexLiteral.pattern}/`); this.writeRawString(regexLiteral.pattern); }); } -export function genObjectExpression(this: Generaotr, objectExpression: ObjectExpression) { +export function genObjectExpression(this: Generator, objectExpression: ObjectExpression) { this.writeParanIfNeed(objectExpression.parentheses, () => { this.writeWithBraces(true, () => { for (const def of objectExpression.properties) { @@ -111,7 +113,7 @@ export function genObjectExpression(this: Generaotr, objectExpression: ObjectExp }); }); } -export function genObjectProperty(this: Generaotr, objectProperty: ObjectProperty) { +export function genObjectProperty(this: Generator, objectProperty: ObjectProperty) { this.genPropertyName(objectProperty.key, objectProperty.computed); this.writeToken(SyntaxKinds.ColonPunctuator); this.writeSpace(); @@ -119,7 +121,7 @@ export function genObjectProperty(this: Generaotr, objectProperty: ObjectPropert this.genModuleItem(objectProperty.value); } } -export function genPropertyName(this: Generaotr, propertyName: PropertyName, isComputed: boolean) { +export function genPropertyName(this: Generator, propertyName: PropertyName, isComputed: boolean) { if (isComputed) { this.writeToken(SyntaxKinds.BracketLeftPunctuator); this.genModuleItem(propertyName); @@ -128,7 +130,7 @@ export function genPropertyName(this: Generaotr, propertyName: PropertyName, isC this.genModuleItem(propertyName); } } -export function genObjectMethod(this: Generaotr, objectMethod: ObjectMethodDefinition) { +export function genObjectMethod(this: Generator, objectMethod: ObjectMethodDefinition) { if (objectMethod.async) { this.writeRawString("async"); this.writeSpace(); @@ -141,14 +143,14 @@ export function genObjectMethod(this: Generaotr, objectMethod: ObjectMethodDefin this.genFunctionParam(objectMethod.params); this.genFunctionBody(objectMethod.body); } -export function genObjectAccessor(this: Generaotr, objectAccessor: ObjectAccessor) { +export function genObjectAccessor(this: Generator, objectAccessor: ObjectAccessor) { this.writeRawString(objectAccessor.type); this.writeSpace(); this.genPropertyName(objectAccessor.key, objectAccessor.computed); this.genFunctionParam(objectAccessor.params); this.genFunctionBody(objectAccessor.body); } -export function genArrayExpression(this: Generaotr, arrayExpression: ArrayExpression) { +export function genArrayExpression(this: Generator, arrayExpression: ArrayExpression) { this.writeParanIfNeed(arrayExpression.parentheses, () => { this.writeToken(SyntaxKinds.BracketLeftPunctuator); if (arrayExpression.elements[0]) this.genModuleItem(arrayExpression.elements[0]); @@ -159,7 +161,7 @@ export function genArrayExpression(this: Generaotr, arrayExpression: ArrayExpres this.writeToken(SyntaxKinds.BracketRightPunctuator); }); } -export function genFunctionExpression(this: Generaotr, functionExpression: FunctionExpression) { +export function genFunctionExpression(this: Generator, functionExpression: FunctionExpression) { this.writeParanIfNeed(functionExpression.parentheses, () => { if (functionExpression.async) { this.writeRawString("async"); @@ -177,9 +179,10 @@ export function genFunctionExpression(this: Generaotr, functionExpression: Funct this.genFunctionParam(functionExpression.params); this.writeSpace(); this.genFunctionBody(functionExpression.body); + this.writeLineTerminator(); }); } -export function genArrowFunctionExpression(this: Generaotr, arrowExpr: ArrorFunctionExpression) { +export function genArrowFunctionExpression(this: Generator, arrowExpr: ArrorFunctionExpression) { this.writeParanIfNeed(arrowExpr.parentheses, () => { if (arrowExpr.async) { this.writeRawString("async"); @@ -192,20 +195,20 @@ export function genArrowFunctionExpression(this: Generaotr, arrowExpr: ArrorFunc this.genModuleItem(arrowExpr.body); }); } -export function genSpreadElement(this: Generaotr, spreadElement: SpreadElement) { +export function genSpreadElement(this: Generator, spreadElement: SpreadElement) { this.writeParanIfNeed(spreadElement.parentheses, () => { this.writeToken(SyntaxKinds.SpreadOperator); this.genModuleItem(spreadElement.argument); }); } -export function genAwaitExpression(this: Generaotr, awaitElement: AwaitExpression) { +export function genAwaitExpression(this: Generator, awaitElement: AwaitExpression) { this.writeParanIfNeed(awaitElement.parentheses, () => { this.writeRawString("await"); this.writeSpace(); this.genModuleItem(awaitElement.argument); }); } -export function genNewExpression(this: Generaotr, newExpression: NewExpression) { +export function genNewExpression(this: Generator, newExpression: NewExpression) { this.writeParanIfNeed(newExpression.parentheses, () => { this.writeToken(SyntaxKinds.NewKeyword); this.writeSpace(); @@ -217,7 +220,7 @@ export function genNewExpression(this: Generaotr, newExpression: NewExpression) }); }); } -export function genMemberExpression(this: Generaotr, memberExpression: MemberExpression) { +export function genMemberExpression(this: Generator, memberExpression: MemberExpression) { this.writeParanIfNeed(memberExpression.parentheses, () => { this.genModuleItem(memberExpression.object); if (memberExpression.computed) { @@ -237,7 +240,7 @@ export function genMemberExpression(this: Generaotr, memberExpression: MemberExp } }); } -export function genCallExpression(this: Generaotr, callExpression: CallExpression) { +export function genCallExpression(this: Generator, callExpression: CallExpression) { this.writeParanIfNeed(callExpression.parentheses, () => { this.genModuleItem(callExpression.callee); if (callExpression.optional) { @@ -246,16 +249,17 @@ export function genCallExpression(this: Generaotr, callExpression: CallExpressio this.writeWithParan(() => { for (const item of callExpression.arguments) { this.genModuleItem(item); + this.writeToken(SyntaxKinds.CommaToken); } }); }); } -export function genChainExpression(this: Generaotr, chainExpression: ChainExpression) { +export function genChainExpression(this: Generator, chainExpression: ChainExpression) { this.writeParanIfNeed(chainExpression.parentheses, () => { this.genModuleItem(chainExpression.expression); }); } -export function genUpdateExpression(this: Generaotr, updateExpression: UpdateExpression) { +export function genUpdateExpression(this: Generator, updateExpression: UpdateExpression) { this.writeParanIfNeed(updateExpression.parentheses, () => { if (updateExpression.prefix) { this.writeToken(updateExpression.operator); @@ -268,14 +272,14 @@ export function genUpdateExpression(this: Generaotr, updateExpression: UpdateExp } }); } -export function genUnaryExpression(this: Generaotr, unaryExpression: UnaryExpression) { +export function genUnaryExpression(this: Generator, unaryExpression: UnaryExpression) { this.writeParanIfNeed(unaryExpression.parentheses, () => { this.writeToken(unaryExpression.operator); this.writeSpace(); this.genModuleItem(unaryExpression.argument); }); } -export function genBinaryExpression(this: Generaotr, binaryExpression: BinaryExpression) { +export function genBinaryExpression(this: Generator, binaryExpression: BinaryExpression) { this.writeParanIfNeed(binaryExpression.parentheses, () => { this.genModuleItem(binaryExpression.left); this.writeSpace(); @@ -284,7 +288,7 @@ export function genBinaryExpression(this: Generaotr, binaryExpression: BinaryExp this.genModuleItem(binaryExpression.right); }); } -export function genConditionalExpression(this: Generaotr, conditionalExpression: ConditionalExpression) { +export function genConditionalExpression(this: Generator, conditionalExpression: ConditionalExpression) { this.writeParanIfNeed(conditionalExpression.parentheses, () => { this.genModuleItem(conditionalExpression.test); this.writeToken(SyntaxKinds.QustionOperator); @@ -296,7 +300,7 @@ export function genConditionalExpression(this: Generaotr, conditionalExpression: this.genModuleItem(conditionalExpression.alter); }); } -export function genYieldExpression(this: Generaotr, yeildExpression: YieldExpression) { +export function genYieldExpression(this: Generator, yeildExpression: YieldExpression) { this.writeParanIfNeed(yeildExpression.parentheses, () => { this.writeToken(SyntaxKinds.YieldKeyword); if (yeildExpression.delegate) { @@ -308,7 +312,7 @@ export function genYieldExpression(this: Generaotr, yeildExpression: YieldExpres } }); } -export function genAssignmentExpression(this: Generaotr, assigmentExpression: AssigmentExpression) { +export function genAssignmentExpression(this: Generator, assigmentExpression: AssigmentExpression) { this.writeParanIfNeed(assigmentExpression.parentheses, () => { this.genModuleItem(assigmentExpression.left); this.writeSpace(); @@ -317,7 +321,7 @@ export function genAssignmentExpression(this: Generaotr, assigmentExpression: As this.genModuleItem(assigmentExpression.right); }); } -export function genSequenceExpression(this: Generaotr, sequenceExpression: SequenceExpression) { +export function genSequenceExpression(this: Generator, sequenceExpression: SequenceExpression) { this.writeParanIfNeed(sequenceExpression.parentheses, () => { this.genModuleItem(sequenceExpression.exprs[0]); for (const expr of sequenceExpression.exprs.slice(1)) { diff --git a/web-infras/generator/src/js/index.ts b/web-infras/generator/src/js/index.ts index 8dfa4450..bd833036 100644 --- a/web-infras/generator/src/js/index.ts +++ b/web-infras/generator/src/js/index.ts @@ -2,3 +2,4 @@ export * from "./program"; export * from "./declaration"; export * from "./statement"; export * from "./expression"; +export * from "./pattern"; diff --git a/web-infras/generator/src/js/pattern.ts b/web-infras/generator/src/js/pattern.ts new file mode 100644 index 00000000..36d41984 --- /dev/null +++ b/web-infras/generator/src/js/pattern.ts @@ -0,0 +1,53 @@ +import { Generator } from "@/src/generator"; +import { + AssignmentPattern, + ObjectPattern, + ObjectPatternProperty, + RestElement, + SyntaxKinds, +} from "web-infra-common"; + +export function genObjectPattern(this: Generator, objectPat: ObjectPattern) { + this.writeWithBraces(false, () => { + this.writeSpace(); + this.genPropertyInObjectPattern(objectPat.properties[0]); + for (const property of objectPat.properties.slice(1)) { + this.writeToken(SyntaxKinds.CommaToken); + this.writeSpace(); + this.genPropertyInObjectPattern(property); + } + this.writeSpace(); + }); +} + +export function genPropertyInObjectPattern( + this: Generator, + property: ObjectPatternProperty | RestElement | AssignmentPattern, +) { + switch (property.kind) { + case SyntaxKinds.ObjectPatternProperty: { + this.genObjectPatternProperty(property); + break; + } + case SyntaxKinds.RestElement: { + this.genRestElement(property); + break; + } + case SyntaxKinds.AssignmentPattern: { + break; + } + } +} + +export function genObjectPatternProperty(this: Generator, objectPatProps: ObjectPatternProperty) { + this.genPropertyName(objectPatProps.key, objectPatProps.computed); + if (objectPatProps.value) { + this.writeToken(SyntaxKinds.ColonPunctuator); + this.writeSpace(); + this.genModuleItem(objectPatProps.value); + } +} +export function genRestElement(this: Generator, restElement: RestElement) { + this.writeToken(SyntaxKinds.SpreadOperator); + this.genModuleItem(restElement.argument); +} diff --git a/web-infras/generator/src/js/program.ts b/web-infras/generator/src/js/program.ts index c2671c05..0f3607b7 100644 --- a/web-infras/generator/src/js/program.ts +++ b/web-infras/generator/src/js/program.ts @@ -1,4 +1,4 @@ -import { Generaotr } from "../index"; +import { Generator } from "@/src/generator"; import { SyntaxKinds, ModuleItem, @@ -50,15 +50,19 @@ import { ArrayExpression, FunctionExpression, ArrorFunctionExpression, + ObjectPattern, + ObjectProperty, + ObjectMethodDefinition, + ObjectAccessor, } from "web-infra-common"; -export function genProgram(this: Generaotr, program: Program) { +export function genProgram(this: Generator, program: Program) { for (const item of program.body) { this.genModuleItem(item); } } -export function genModuleItem(this: Generaotr, item: ModuleItem) { +export function genModuleItem(this: Generator, item: ModuleItem) { switch (item.kind) { /** * Declaration @@ -171,6 +175,15 @@ export function genModuleItem(this: Generaotr, item: ModuleItem) { case SyntaxKinds.ObjectExpression: this.genObjectExpression(item as ObjectExpression); break; + case SyntaxKinds.ObjectProperty: + this.genObjectProperty(item as ObjectProperty); + break; + case SyntaxKinds.ObjectMethodDefintion: + this.genObjectMethod(item as ObjectMethodDefinition); + break; + case SyntaxKinds.ObjectAccessor: + this.genObjectAccessor(item as ObjectAccessor); + break; case SyntaxKinds.ArrayExpression: this.genArrayExpression(item as ArrayExpression); break; @@ -219,5 +232,11 @@ export function genModuleItem(this: Generaotr, item: ModuleItem) { case SyntaxKinds.SequenceExpression: this.genSequenceExpression(item as SequenceExpression); break; + /** + * Pattern + */ + case SyntaxKinds.ObjectPattern: + this.genObjectPattern(item as ObjectPattern); + break; } } diff --git a/web-infras/generator/src/js/statement.ts b/web-infras/generator/src/js/statement.ts index f4263c48..2d0eead2 100644 --- a/web-infras/generator/src/js/statement.ts +++ b/web-infras/generator/src/js/statement.ts @@ -19,9 +19,9 @@ import { SwitchCase, DebuggerStatement, } from "web-infra-common"; -import { Generaotr } from "@/src/index"; +import { Generator } from "@/src/generator"; -export function genIfStatement(this: Generaotr, ifStatement: IfStatement) { +export function genIfStatement(this: Generator, ifStatement: IfStatement) { this.writeToken(SyntaxKinds.IfKeyword); this.writeWithParan(() => { this.genModuleItem(ifStatement.test); @@ -32,7 +32,7 @@ export function genIfStatement(this: Generaotr, ifStatement: IfStatement) { this.genModuleItem(ifStatement.alternative); } } -export function genBlockStatement(this: Generaotr, blockStatement: BlockStatement) { +export function genBlockStatement(this: Generator, blockStatement: BlockStatement) { this.writeWithBraces(true, () => { for (const item of blockStatement.body) { this.writePrefixSpace(); @@ -40,7 +40,7 @@ export function genBlockStatement(this: Generaotr, blockStatement: BlockStatemen } }); } -export function genSwitchStatement(this: Generaotr, switchStatement: SwitchStatement) { +export function genSwitchStatement(this: Generator, switchStatement: SwitchStatement) { this.writeToken(SyntaxKinds.SwitchKeyword); this.writeWithParan(() => { this.genModuleItem(switchStatement.discriminant); @@ -53,7 +53,7 @@ export function genSwitchStatement(this: Generaotr, switchStatement: SwitchState }); this.writeLineTerminator(); } -export function genSwitchCase(this: Generaotr, switchCase: SwitchCase) { +export function genSwitchCase(this: Generator, switchCase: SwitchCase) { if (switchCase.test) { this.writeToken(SyntaxKinds.CaseKeyword); this.genModuleItem(switchCase.test); @@ -66,7 +66,7 @@ export function genSwitchCase(this: Generaotr, switchCase: SwitchCase) { this.genModuleItem(item); } } -export function genForInStatement(this: Generaotr, forInStatement: ForInStatement) { +export function genForInStatement(this: Generator, forInStatement: ForInStatement) { this.writeToken(SyntaxKinds.ForKeyword); this.writeWithParan(() => { this.genModuleItem(forInStatement.left); @@ -76,7 +76,7 @@ export function genForInStatement(this: Generaotr, forInStatement: ForInStatemen this.genModuleItem(forInStatement.body); this.writeLineTerminator(); } -export function genForOfStatement(this: Generaotr, forOfStatement: ForOfStatement) { +export function genForOfStatement(this: Generator, forOfStatement: ForOfStatement) { this.writeToken(SyntaxKinds.ForKeyword); this.writeWithParan(() => { this.genModuleItem(forOfStatement.left); @@ -86,38 +86,41 @@ export function genForOfStatement(this: Generaotr, forOfStatement: ForOfStatemen this.genModuleItem(forOfStatement.body); this.writeLineTerminator(); } -export function genBreakStatement(this: Generaotr, breakStatement: BreakStatement) { +export function genBreakStatement(this: Generator, breakStatement: BreakStatement) { this.writeToken(SyntaxKinds.BreakKeyword); if (breakStatement.label) { this.genModuleItem(breakStatement.label); } this.writeLineTerminator(); } -export function genContinueStatement(this: Generaotr, continueStatement: ContinueStatement) { +export function genContinueStatement(this: Generator, continueStatement: ContinueStatement) { this.writeToken(SyntaxKinds.ContinueKeyword); if (continueStatement.label) { this.genModuleItem(continueStatement.label); } this.writeLineTerminator(); } -export function genReturnStatement(this: Generaotr, returnStatement: ReturnStatement) { +export function genReturnStatement(this: Generator, returnStatement: ReturnStatement) { this.writeToken(SyntaxKinds.ReturnKeyword); - if (returnStatement.argu) this.genModuleItem(returnStatement.argu); + if (returnStatement.argu) { + this.writeSpace(); + this.genModuleItem(returnStatement.argu); + } this.writeLineTerminator(); } -export function genLabeledStatement(this: Generaotr, labeledStatement: LabeledStatement) { +export function genLabeledStatement(this: Generator, labeledStatement: LabeledStatement) { this.genModuleItem(labeledStatement.label); this.writeToken(SyntaxKinds.CommaToken); this.genModuleItem(labeledStatement.body); } -export function genWhileStatment(this: Generaotr, whileStatement: WhileStatement) { +export function genWhileStatment(this: Generator, whileStatement: WhileStatement) { this.writeToken(SyntaxKinds.WhileKeyword); this.writeWithParan(() => { this.genModuleItem(whileStatement.test); }); this.genModuleItem(whileStatement.body); } -export function genDoWhileStatement(this: Generaotr, doWhileStatement: DoWhileStatement) { +export function genDoWhileStatement(this: Generator, doWhileStatement: DoWhileStatement) { this.writeToken(SyntaxKinds.DoKeyword); this.genModuleItem(doWhileStatement.body); this.writeToken(SyntaxKinds.WhileKeyword); @@ -125,7 +128,7 @@ export function genDoWhileStatement(this: Generaotr, doWhileStatement: DoWhileSt this.genModuleItem(doWhileStatement.test); }); } -export function genTryStatement(this: Generaotr, tryStatement: TryStatement) { +export function genTryStatement(this: Generator, tryStatement: TryStatement) { this.writeToken(SyntaxKinds.TrueKeyword); this.genBlockStatement(tryStatement.block); this.writeToken(SyntaxKinds.CatchKeyword); @@ -142,7 +145,7 @@ export function genTryStatement(this: Generaotr, tryStatement: TryStatement) { }); } } -export function genCatchClause(this: Generaotr, catchClause: CatchClause) { +export function genCatchClause(this: Generator, catchClause: CatchClause) { this.writeToken(SyntaxKinds.CatchKeyword); if (catchClause.param) { this.writeWithParan(() => { @@ -151,12 +154,12 @@ export function genCatchClause(this: Generaotr, catchClause: CatchClause) { } this.genBlockStatement(catchClause.body); } -export function genThrowStatment(this: Generaotr, throwStatement: ThrowStatement) { +export function genThrowStatment(this: Generator, throwStatement: ThrowStatement) { this.writeToken(SyntaxKinds.ThrowKeyword); this.genModuleItem(throwStatement.argu); this.writeLineTerminator(); } -export function genWithStatement(this: Generaotr, withStatement: WithStatement) { +export function genWithStatement(this: Generator, withStatement: WithStatement) { this.writeToken(SyntaxKinds.WithKeyword); this.writeWithParan(() => { this.genModuleItem(withStatement.object); @@ -164,12 +167,12 @@ export function genWithStatement(this: Generaotr, withStatement: WithStatement) this.writeToken(SyntaxKinds.ColonPunctuator); this.genModuleItem(withStatement.body); } -export function genDebugerStatement(this: Generaotr, _debuggerStatement: DebuggerStatement) { +export function genDebugerStatement(this: Generator, _debuggerStatement: DebuggerStatement) { this.writeToken(SyntaxKinds.DebuggerKeyword); this.writeToken(SyntaxKinds.ColonPunctuator); this.writeLineTerminator(); } -export function genExpressionStatement(this: Generaotr, exprStatement: ExpressionStatement) { +export function genExpressionStatement(this: Generator, exprStatement: ExpressionStatement) { this.genModuleItem(exprStatement.expr); this.writeToken(SyntaxKinds.SemiPunctuator); this.writeLineTerminator(); diff --git a/web-infras/generator/tsconfig.build.json b/web-infras/generator/tsconfig.build.json new file mode 100644 index 00000000..bfd73f64 --- /dev/null +++ b/web-infras/generator/tsconfig.build.json @@ -0,0 +1,114 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ESNext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, + "paths": { + "@/src/*": ["src/*"] + } /* Specify a set of entries that re-map imports to additional lookup locations. */, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} diff --git a/web-infras/generator/tsconfig.json b/web-infras/generator/tsconfig.json index f82f1e9b..7743ac11 100644 --- a/web-infras/generator/tsconfig.json +++ b/web-infras/generator/tsconfig.json @@ -25,7 +25,7 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "CommonJS", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ diff --git a/web-infras/parser/tsconfig.json b/web-infras/parser/tsconfig.json index 8d214b34..b8f9d1d7 100644 --- a/web-infras/parser/tsconfig.json +++ b/web-infras/parser/tsconfig.json @@ -1,115 +1,115 @@ { - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "CommonJS", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ - "paths": { - "@/src/*": ["src/*"] - }, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "ts-node": { - "require": ["tsconfig-paths/register"] - } + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "CommonJS", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@/src/*": ["src/*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "ts-node": { + "require": ["tsconfig-paths/register"] } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d93f71bb..b95bceb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5927,6 +5927,32 @@ __metadata: languageName: unknown linkType: soft +"web-infra-bundler@workspace:web-infras/bundler": + version: 0.0.0-use.local + resolution: "web-infra-bundler@workspace:web-infras/bundler" + dependencies: + "@eslint/js": "npm:^9.14.0" + "@rollup/plugin-typescript": "npm:^11.1.5" + "@swc/core": "npm:^1.7.10" + "@types/eslint": "npm:^9" + "@types/eslint__js": "npm:^8.42.3" + chalk: "npm:4.1.2" + eslint: "npm:^9.14.0" + nodemon: "npm:^3.0.1" + prettier: "npm:^3.3.2" + rollup: "npm:^4.1.4" + rollup-plugin-dts: "npm:^6.1.0" + ts-node: "npm:^10.9.1" + tsconfig-paths: "npm:^4.2.0" + tslib: "npm:^2.6.2" + typescript: "npm:^5.6.3" + typescript-eslint: "npm:^8.13.0" + web-infra-common: "workspace:*" + web-infra-generator: "workspace:*" + web-infra-parser: "workspace:*" + languageName: unknown + linkType: soft + "web-infra-common@workspace:*, web-infra-common@workspace:web-infras/common": version: 0.0.0-use.local resolution: "web-infra-common@workspace:web-infras/common" @@ -5946,7 +5972,7 @@ __metadata: languageName: unknown linkType: soft -"web-infra-generator@workspace:web-infras/generator": +"web-infra-generator@workspace:*, web-infra-generator@workspace:web-infras/generator": version: 0.0.0-use.local resolution: "web-infra-generator@workspace:web-infras/generator" dependencies: