Skip to content

Commit

Permalink
🗺️ Implementing Set and Map ad more
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashu11-A committed Dec 14, 2024
1 parent bb35785 commit d404bf1
Show file tree
Hide file tree
Showing 26 changed files with 611 additions and 194 deletions.
12 changes: 11 additions & 1 deletion build/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Watcher } from './class/Watcher.js'
import { TypeExtractor } from './lib/TypeExtractor.js'
import { WatcherTypes } from './types/WatcherTypes.js'
import { generateDtsBundle } from 'dts-bundle-generator'
import { cp, mkdir, writeFile } from 'fs/promises'
import { cp, mkdir, readFile, writeFile } from 'fs/promises'

const activeProcesses = new Map<string, NodeJS.Timeout>()

Expand Down Expand Up @@ -100,6 +100,16 @@ const executeBuildProcess = async () => {
await writeFile('dist/cjs/package.json', JSON.stringify({ type: 'commonjs' }, null, 2))
await writeFile('dist/mjs/package.json', JSON.stringify({ type: 'module' }, null, 2))

const filePaths = ['dist/mjs/index.js','dist/cjs/index.cjs' ]
for (const path of filePaths) {
const code: string[] = []

code.push('#!/usr/bin/env node')
code.push(await readFile(path, { encoding: 'utf8' }))

await writeFile(path, code.join('\n'), { encoding: 'utf-8' })
}

const dtsPath = join(process.cwd(), 'dist/types/index.d.ts')
const dtsCode = generateDtsBundle([{
filePath: join(process.cwd(), 'src/index.ts'),
Expand Down
20 changes: 20 additions & 0 deletions src/class/ClassMemory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export class ClassMemory {
public static all = new Map<string, ClassMemory>()

/**
* Nome da classe utilizada
*/
name: string

/**
* Constrante que usa a class
*/
constant: string

constructor (options: ClassMemory) {
this.name = options.name
this.constant = options.constant

ClassMemory.all.set(this.name, this)
}
}
77 changes: 54 additions & 23 deletions src/class/transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@ import { join } from 'path'
import type { Expression, PrivateIdentifier, Program } from '../../node_modules/meriyah/dist/src/estree.js'
import { Method } from './methods.js'

interface TransformOptions {
path: string
type TransformOptions = {
removeComments?: boolean
sourcePath: string
cwd?: string
debug?: boolean
}

export class Transpiler {
public ast: Program
static tabs: number = 0
static options: TransformOptions
static globalDeclarations: Record<string, string> = {}
public ast: Program
static globalDeclarations = new Map<string, string>()

constructor(options: TransformOptions) {
Transpiler.options = {
...options,
path: join(options.cwd ?? '', options.path)
sourcePath: join(options.cwd ?? '', options.sourcePath)
}

this.ast = Transpiler.loader()
Expand All @@ -32,7 +33,7 @@ export class Transpiler {
global.loggings.config({ format: '{message}', level: Transpiler.options?.debug ? 'debug' : 'info' })

console.debug(Rgb(249, 248, 113) + 'Debug Mode!')
console.debug(Rgb(132, 94, 194) + 'Transpiling:', Rgb(255, 199, 95) + Transpiler.options.path)
console.debug(Rgb(132, 94, 194) + 'Transpiling:', Rgb(255, 199, 95) + Transpiler.options.sourcePath)
}

/**
Expand All @@ -42,33 +43,52 @@ export class Transpiler {
* @returns {Promise<(Program)>}
*/
static loader(code?: string): Program {
if (code === undefined) code = readFileSync(Transpiler.options.path, { encoding: 'utf-8' })
if (code === undefined) code = readFileSync(Transpiler.options.sourcePath, { encoding: 'utf-8' })
const AST = new AbstractSyntaxTree(code)
return AST
}

parser (ast?: (Program)) {
const code: string[] = []
parser(ast?: Program) {
ast = ast ?? this.ast

code.push('#!/bin/bash\n')

let output: string[] = []

for (const body of ast.body) {
const method = Method.all.get(body.type)

if (method === undefined) { console.debug(Rgb(255, 220, 0) + `[${body.type}] ` + Colors('red', 'Not defined')); continue }
const source = method.interaction.parser(body, { type: method.interaction.type, parser: method.interaction.parser, subprocess: method.subprocess }) as string

for (const [, codeSource] of Object.entries(Transpiler.globalDeclarations)) {
code.push(codeSource)

if (!method) {
console.debug(Rgb(255, 220, 0) + `[${body.type}] ` + Colors('red', 'Not defined'))
continue
}

Transpiler.globalDeclarations = {}
code.push(source)
const source = method.interaction.parser(body, {
type: method.interaction.type,
parser: method.interaction.parser,
subprocess: method.subprocess
}) as string

output.push(source)
}

const globalDeclarations = Array.from(Transpiler.globalDeclarations.values())
Transpiler.globalDeclarations.clear()

output.unshift(...globalDeclarations)

if (Transpiler.options.removeComments) {
output = output.map((content) => {
const array = content.split('\n')
for (const [index, value] of Object.entries(array)) {
array[Number(index)] = (value.trim()).startsWith('#') ? '(REMOVE)' : value
}
return array.filter((line) => line !== '(REMOVE)').join('\n')
})
}

return breakLines(code)
output.unshift('#!/bin/bash\n')

return breakLines(output)
}


/**
* Retorna o operador equivalente do javascript para o shell script
Expand Down Expand Up @@ -100,16 +120,27 @@ export class Transpiler {
* @param {(string | string[])} content
* @returns {string}
*/
static parseReturnString(type: Expression['type'] | PrivateIdentifier['type'], content: string | string[]): string {
static parseReturnString(type: Expression['type'] | PrivateIdentifier['type'], content: string | string[] | boolean | number): string {
console.log(type)
console.log(content)
content = Array.isArray(content)
? content.map((value) => String(value).trim())
: typeof content === 'boolean'
? (content === true ? '0' : '1')
: typeof content === 'number'
? content
: content.trim()

switch (type) {
// Identifier são constantes: const num = 0
case 'Identifier': return `"$${content}"`
// Literal são strings ou numbers
case 'Literal': return !Number.isNaN(Number(content)) ? `${content}` : `"${content}"`
case 'CallExpression': return `$(${content})`
case 'CallExpression': return `$(eval ${content})`
case 'ArrayExpression': return `(${(content as string[]).join(' ')})`
case 'ArrowFunctionExpression': return `${content}`
case 'ObjectExpression': return `${content}`
// case 'MemberExpression': return `$(${content})`
}

// console.debug(Colors('red', `[parseReturnString] Not identified: ${type} ${content}`))
Expand Down
4 changes: 2 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const code = new Map<string, string>();
const files = await glob(`${content}/**/*.{js,ts}`, { cwd: process.cwd() })

for (const file of files) {
const output = new Transpiler({ path: file, debug: false }).parser()
const output = new Transpiler({ sourcePath: file, debug: false }).parser()
code.set(file.split('/').slice(1).join('/'), output)
}
},
Expand All @@ -64,7 +64,7 @@ const code = new Map<string, string>();
hasString: true,
async function(content) {
if (content === undefined) throw new Error('File not expecificate')
const output = new Transpiler({ path: content, debug: JSON.parse(process.env['transpilerDebug'] ?? 'false') }).parser()
const output = new Transpiler({ sourcePath: content, debug: JSON.parse(process.env['transpilerDebug'] ?? 'false') }).parser()
code.set(content, output)
},
},
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import './methods/expressions/ClassDeclaration.ts'
import './methods/expressions/FunctionExpression.ts'
import './methods/expressions/Identifier.ts'
import './methods/expressions/Literal.ts'
import './methods/expressions/MemberExpression copy.ts'
import './methods/expressions/MemberExpression.ts'
import './methods/expressions/MetaProperty.ts'
import './methods/expressions/NewExpression.ts'
Expand Down
21 changes: 20 additions & 1 deletion src/loader.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
import { Colors } from '@loggings/beta'
import { readFileSync } from 'fs'
import { globSync } from 'glob'
import { basename, dirname, join } from 'path'
import { basename, dirname, extname, join } from 'path'
import { fileURLToPath } from 'url'

const rootFile = basename(fileURLToPath(import.meta.url))
const rootPath = dirname(fileURLToPath(import.meta.url))
export const getTransformers = () => rootFile === 'index.js'
? globSync(join(rootPath, '..', 'transformers/**/*.sh'), { cwd: join('..', rootPath) })
: globSync('src/transformers/shellscript/**/*.sh', { cwd: process.cwd() })

export const getTransformer = (transformer: string) => {
const files = new Map<string, string>()

if (rootFile === 'index.js') {
globSync(join(rootPath, '..', 'transformers/**/*.sh'), { cwd: join('..', rootPath) })
.forEach((filePath) => files.set(basename(filePath, extname(filePath)), filePath))
} else {
globSync('src/transformers/shellscript/**/*.sh', { cwd: process.cwd() })
.forEach((filePath) => files.set(basename(filePath, extname(filePath)), filePath))
}

const filePath = files.get(transformer)
if (filePath) return readFileSync(filePath, { encoding: 'utf8' })
console.debug(Colors('red', `Transformer ${transformer} not found!`))
return ''
}
6 changes: 4 additions & 2 deletions src/methods/expressions/ArrowFunctionExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ new Method({
const result = options.subprocess(expression.body.type, expression.body) as string
const params = expression.params.map((param) => options.subprocess(param.type, param))

Transpiler.tabs++
for (const [index, param] of Object.entries(params)) {
code.push(getTabs(Transpiler.tabs) + `local ${param}=$${Number(index) + 1}`)
code.push(`${getTabs(Transpiler.tabs)}local ${param}=$${Number(index) + 1}`)
}

Transpiler.tabs--

code.push(result)

return breakLines(code)
Expand Down
52 changes: 42 additions & 10 deletions src/methods/expressions/CallExpression.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { randomUUID } from 'crypto'
import { existsSync, readFileSync } from 'fs'
import { basename } from 'path'
import type { Expression, MemberExpression, SpreadElement } from '../../../node_modules/meriyah/dist/src/estree.js'
import { Method } from '../../class/methods.js'
import { Transpiler } from '../../class/transpiler.js'
import { getTransformers } from '../../loader.js'
import { basename } from 'path'
import type { Expression, MemberExpression, SpreadElement } from '../../../node_modules/meriyah/dist/src/estree.js'
import { breakLines } from '../../libs/breakLines.js'
import { getTabs } from '../../libs/getTabs.js'
import { getTransformer, getTransformers } from '../../loader.js'
import type { ASTNode } from '../../types/methods.js'

/**
* Formata chamadas de funções junto com suas args
Expand All @@ -20,9 +24,39 @@ new Method({
if (expression.callee.type === 'MemberExpression') {
const callee = expression.callee as MemberExpression
const args = expression.arguments as (Expression | SpreadElement)[]
const code: string[] = []
const values: Array<{ type: ASTNode['type'], value: string }> = []
const variables = new Map<string, string>()

args.forEach((arg) =>{
const parsed = Transpiler.parseReturnString(arg.type, options.subprocess(arg.type, arg))

values.push({ type: arg.type, value: parsed })
})

values.forEach((item) => {
switch (item.type) {
case 'CallExpression': {
const variableName = `result_${randomUUID().replaceAll('-', '')}`

variables.set(item.value, `$${variableName}`)
code.push(`${getTabs(Transpiler.tabs)}${variableName}=${item.value}`)
break
}
default: {
variables.set(item.value, item.value)
}
}

})

// Isso vai para MemberExpression, se não ficou obvio
return options.subprocess<typeof callee.type, string>(callee.type, callee, args.map((arg) => Transpiler.parseReturnString(arg.type, options.subprocess(arg.type, arg) as string)).join(' '))
code.push(options.subprocess<typeof callee.type, Map<string, string>>(
callee.type,
callee,
variables
) as string)
return breakLines(code)
} else {
const functionName = expression.callee.name
const transformers: Record<string, string> = {}
Expand All @@ -32,21 +66,19 @@ new Method({
* Aqui é definido o transformers de certas funções, como o fetch, onde é puxado a função que trata o fetch entre curl e wget, e o isCommand para validar se existe as dependencias
*/
switch (functionName) {
case 'fetch': {
const fetchCode = readFileSync(transformers['fetch.sh'], { encoding: 'utf-8' })
const isCommandCode = readFileSync(transformers['isCommand.sh'], { encoding: 'utf-8' })
Transpiler.globalDeclarations = Object.assign({ 'isCommand': isCommandCode, 'fetch': fetchCode }, Transpiler.globalDeclarations)
case 'fetch': {
Transpiler.globalDeclarations.set('isCommand', getTransformer('isCommand.sh'))
Transpiler.globalDeclarations.set('fetch', getTransformer('fetch.sh'))
break
}
}

const args = expression.arguments.map((arg) => Transpiler.parseReturnString(arg.type, options.subprocess(arg.type, arg) as string)) as (string)[]

const transformer = transformers[`${functionName}.sh`]

if (existsSync(transformer)) {
const transformerCode = readFileSync(transformer, { encoding: 'utf-8' })
Transpiler.globalDeclarations = Object.assign(Transpiler.globalDeclarations, { [functionName]: transformerCode })
Transpiler.globalDeclarations.set(functionName, transformerCode)
}

return `${functionName} ${args.length > 0 ? args.join(' ') : ''}`
Expand Down
Loading

0 comments on commit d404bf1

Please sign in to comment.