diff --git a/.changeset/fine-ways-help.md b/.changeset/fine-ways-help.md new file mode 100644 index 00000000..fb968a42 --- /dev/null +++ b/.changeset/fine-ways-help.md @@ -0,0 +1,5 @@ +--- +'@kitql/internals': patch +--- + +improve perf ast pasting & deprecate parseTs in favor of parse diff --git a/.prettierignore b/.prettierignore index 35a40c49..54f34a67 100644 --- a/.prettierignore +++ b/.prettierignore @@ -22,3 +22,4 @@ templates/ *.svg ab.d.ts .astro +.VSCodeCounter/ \ No newline at end of file diff --git a/packages/internals/package.json b/packages/internals/package.json index 7de20f00..e411041e 100644 --- a/packages/internals/package.json +++ b/packages/internals/package.json @@ -45,6 +45,7 @@ }, "dependencies": { "@babel/parser": "catalog:tooling", + "@babel/types": "catalog:tooling", "@kitql/helpers": "workspace:*", "recast": "catalog:tooling", "svelte": "catalog:svelte-dep" diff --git a/packages/internals/src/lib/ast/ast.spec.ts b/packages/internals/src/lib/ast/ast.spec.ts index e0993a1a..c007f26a 100644 --- a/packages/internals/src/lib/ast/ast.spec.ts +++ b/packages/internals/src/lib/ast/ast.spec.ts @@ -1,39 +1,134 @@ import { describe, expect, it } from 'vitest' -import { extractHtmlElementAttr_Text, format, parseTs } from './ast.js' +import { read } from '../fs/fs.js' +import { parse, print } from './ast.js' describe('parse', function () { - it('parseJS with decorators', async function () { - const parsed = parseTs(` + it('parse with decorators', async function () { + const parsed = parse(` const a = 1 const b = 2 @annotation class Test {} `) - expect(parsed.type).toMatchInlineSnapshot(`"Program"`) + expect(parsed.type).toMatchInlineSnapshot(`"File"`) }) - it('parseJS with top level await', async function () { - const parsed = parseTs(` + it('parse with top level await', async function () { + const parsed = parse(` await fetch('https://www.google.com') `) - expect(parsed.body.length).toBe(1) - expect(parsed.body[0].type).toBe('ExpressionStatement') + expect(parsed.program.body.length).toBe(1) + expect(parsed.program.body[0].type).toBe('ExpressionStatement') }) +}) + +describe('print', function () { + it('simple', function () { + const code = `const a = 1; +const b = "hello" + ` + const ast = parse(code) + expect(print(ast).code).toMatchInlineSnapshot(` + "const a = 1; + const b = "hello";" + `) + }) + + it('null', function () { + const ast = parse(null!) + expect(print(ast).code).toMatchInlineSnapshot(`""`) + }) + + it('@BackendMethod file', function () { + const code = read('../vite-plugin-stripper/src/shared/actionsController.ts') ?? '' + + const ast = parse(code) + expect(print(ast).code).toMatchInlineSnapshot(` + "// import { performance } from 'perf_hooks' + // import { AUTH_SECRET } from "$env/static/private" + // const helpers = async () => { + // const { AUTH_SECRET } = await import('$env/static/private') + // return { AUTH_SECRET } + // } + // if (import.meta.env.SSR) { + // } + import { BackendMethod, remult, type Allowed } from "remult"; + + export class ActionsController { + @BackendMethod({ + allowed: () => remult.user === undefined + }) + static async read(info: Allowed) { + const { + plop + } = await import("./toto.js"); + + const { + AUTH_SECRET + } = await import("$env/static/private"); + + const { + performance: p + } = await import("perf_hooks"); + + const start = p.now(); + console.info("AUTH_SECRET", AUTH_SECRET); + const end = p.now(); + console.info(end - start); + plop(); + return AUTH_SECRET + " " + info; + } + }" + `) + }) + + it('@Entity file', function () { + const code = read('../vite-plugin-stripper/src/shared/User.ts') ?? '' + + const ast = parse(code) + expect(print(ast).code).toMatchInlineSnapshot(` + "// Only unauthenticated users can call this method + import { BackendMethod, Entity, Fields, remult, type Allowed } from "remult"; + import { AUTH_SECRET } from "$env/static/private"; + + @Entity("users", { + allowApiCrud: true, + + backendPrefilter: () => { + console.info("AUTH_SECRET_backendPrefilter", AUTH_SECRET); + console.info("backendPrefilter_top_secret"); + return {}; + }, + + backendPreprocessFilter: f => { + console.info("AUTH_SECRET_backendPreprocessFilter", AUTH_SECRET); + console.info("backendPreprocessFilter_top_secret"); + return f; + }, + + sqlExpression: () => { + console.info("AUTH_SECRET_sqlExpression", AUTH_SECRET); + console.info("sqlExpression_top_secret"); + return "users"; + } + }) + export class User { + @Fields.uuid() + id = ""; + + @Fields.string() + name = ""; - it('find hardcoded a_href, img_src', async function () { - const list = extractHtmlElementAttr_Text('/src/routes/+page.svelte', [ - { type: 'a', attr: 'href' }, - { type: 'img', attr: 'src' }, - ]) - - expect(list.map((c) => format(c))).toMatchInlineSnapshot(` - [ - "/src/routes/+page.svelte:9:9 a href www.google.com", - "/src/routes/+page.svelte:13:10 img src test", - "/src/routes/+page.svelte:16:10 a href www.google.com", - ] + @BackendMethod({ + allowed: () => remult.user === undefined + }) + static async hi(info: Allowed) { + console.info("AUTH_SECRET", AUTH_SECRET); + return AUTH_SECRET + " " + info; + } + }" `) }) }) diff --git a/packages/internals/src/lib/ast/ast.ts b/packages/internals/src/lib/ast/ast.ts index fee09d3a..8d039c26 100644 --- a/packages/internals/src/lib/ast/ast.ts +++ b/packages/internals/src/lib/ast/ast.ts @@ -1,85 +1,33 @@ -import { parse } from '@babel/parser' +import babel from '@babel/parser' import * as recast from 'recast' -import { prettyPrint as recastPrettyPrint } from 'recast' -import { parse as parseSvelte } from 'svelte/compiler' -// @ts-ignore -import type { TemplateNode } from 'svelte/types/compiler/interfaces' - -import { read } from '../fs/fs.js' export type Statement = recast.types.namedTypes.Statement +export type ParseResult = babel.ParseResult +export const { visit, builders } = recast.types -export { recastPrettyPrint as prettyPrint } - -// very basic -type ElementAttr = { type: 'a' | 'img'; attr: 'href' | 'src' } -type Found = { - element: ElementAttr - pathFile: string - line: number - column: number - type: string - raw: string - data: string -} +/** @deprecated Use `parse` instead */ +export function parseTs(source: string | null) { + const parsed = babel.parse(source ?? '', { + sourceType: 'module', + plugins: ['typescript', 'importAssertions', 'decorators-legacy'], + }) -export function format(f: Found) { - const str = `${f.pathFile}:${f.line}:${f.column} ${f.element.type} ${f.element.attr} ${f.data}` - // console.log(`str`, str) - return str + return parsed.program as ParseResult['program'] } -export function extractHtmlElementAttr_Text(pathFile: string, elements: ElementAttr[]) { - const source = read(process.cwd() + pathFile) ?? '' - const parsed = parseSvelte(source) - - const found: Found[] = [] - - function getLineAndColumn(index: number): { line: number; column: number } { - const lines = source.substring(0, index).split('\n') - const line = lines.length - const column = lines[lines.length - 1].length + 1 // +1 for 1-based index - return { line, column } - } - - function traverse(node: TemplateNode) { - elements.forEach((element) => { - if (node.type === 'Element' && node.name === element.type) { - const hrefAttribute = node.attributes.find( - (attr: { name: string }) => attr.name === element.attr, - ) - if (hrefAttribute && hrefAttribute.value.length && hrefAttribute.value[0].type === 'Text') { - const { line, column } = getLineAndColumn(hrefAttribute.start + element.attr.length + 1) - found.push({ - element, - pathFile, - line, - column, - type: hrefAttribute.value[0].type, - raw: hrefAttribute.value[0].raw, - data: hrefAttribute.value[0].data, - }) - } - } +export function parse(code_ast: string | ParseResult) { + if (code_ast === null || typeof code_ast === 'string') { + const parsed = babel.parse(code_ast ?? '', { + sourceType: 'module', + plugins: ['typescript', 'importAssertions', 'decorators-legacy'], }) - if (node.children) { - node.children.forEach((child: TemplateNode) => traverse(child)) - } + return parsed } - traverse(parsed.html) - - return found + return code_ast } -export function parseTs(source: string | null) { - const parsed = parse(source ?? '', { - plugins: ['typescript', 'importAssertions', 'decorators-legacy'], - sourceType: 'module', - }).program as recast.types.namedTypes.Program - - return parsed +export function print(node: recast.types.namedTypes.Program, options?: recast.Options) { + return recast.prettyPrint(node, options) } - -export const { visit, builders } = recast.types diff --git a/packages/internals/src/lib/ast/astHtml.spec.ts b/packages/internals/src/lib/ast/astHtml.spec.ts new file mode 100644 index 00000000..2bb3f22e --- /dev/null +++ b/packages/internals/src/lib/ast/astHtml.spec.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest' + +import { extractHtmlElementAttr_Text, formatHtmlError } from './astHtml.js' + +describe('parse', function () { + it('find hardcoded a_href, img_src', async function () { + const list = extractHtmlElementAttr_Text('/src/routes/+page.svelte', [ + { type: 'a', attr: 'href' }, + { type: 'img', attr: 'src' }, + ]) + + expect(list.map((c) => formatHtmlError(c))).toMatchInlineSnapshot(` + [ + "/src/routes/+page.svelte:9:9 a href www.google.com", + "/src/routes/+page.svelte:13:10 img src test", + "/src/routes/+page.svelte:16:10 a href www.google.com", + ] + `) + }) +}) diff --git a/packages/internals/src/lib/ast/astHtml.ts b/packages/internals/src/lib/ast/astHtml.ts new file mode 100644 index 00000000..27f8714f --- /dev/null +++ b/packages/internals/src/lib/ast/astHtml.ts @@ -0,0 +1,67 @@ +import { parse as parseSvelte } from 'svelte/compiler' +// @ts-ignore +import type { TemplateNode } from 'svelte/types/compiler/interfaces' + +import { read } from '../fs/fs.js' + +// very basic +type ElementAttr = { type: 'a' | 'img'; attr: 'href' | 'src' } +type Found = { + element: ElementAttr + pathFile: string + line: number + column: number + type: string + raw: string + data: string +} + +export function formatHtmlError(f: Found) { + const str = `${f.pathFile}:${f.line}:${f.column} ${f.element.type} ${f.element.attr} ${f.data}` + // console.log(`str`, str) + return str +} + +export function extractHtmlElementAttr_Text(pathFile: string, elements: ElementAttr[]) { + const source = read(process.cwd() + pathFile) ?? '' + const parsed = parseSvelte(source) + + const found: Found[] = [] + + function getLineAndColumn(index: number): { line: number; column: number } { + const lines = source.substring(0, index).split('\n') + const line = lines.length + const column = lines[lines.length - 1].length + 1 // +1 for 1-based index + return { line, column } + } + + function traverse(node: TemplateNode) { + elements.forEach((element) => { + if (node.type === 'Element' && node.name === element.type) { + const hrefAttribute = node.attributes.find( + (attr: { name: string }) => attr.name === element.attr, + ) + if (hrefAttribute && hrefAttribute.value.length && hrefAttribute.value[0].type === 'Text') { + const { line, column } = getLineAndColumn(hrefAttribute.start + element.attr.length + 1) + found.push({ + element, + pathFile, + line, + column, + type: hrefAttribute.value[0].type, + raw: hrefAttribute.value[0].raw, + data: hrefAttribute.value[0].data, + }) + } + } + }) + + if (node.children) { + node.children.forEach((child: TemplateNode) => traverse(child)) + } + } + + traverse(parsed.html) + + return found +} diff --git a/packages/vite-plugin-stripper/src/lib/ast.spec.ts b/packages/internals/src/lib/ast/astImports.spec.ts similarity index 90% rename from packages/vite-plugin-stripper/src/lib/ast.spec.ts rename to packages/internals/src/lib/ast/astImports.spec.ts index 30a47145..9f0ebcbe 100644 --- a/packages/vite-plugin-stripper/src/lib/ast.spec.ts +++ b/packages/internals/src/lib/ast/astImports.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import { imports, usage } from './ast.js' +import { imports } from './astImports.js' describe('imports', () => { it('should return an import a', () => { @@ -156,15 +156,3 @@ describe('imports', () => { `) }) }) - -describe('usage', () => { - it('should return an usage', () => { - const code = `import { a } from "lib" - const b = a` - - const importsData = imports(code) - const usageData = usage(code, importsData.importsList) - - expect(usageData.importsList).toMatchInlineSnapshot(`[]`) - }) -}) diff --git a/packages/vite-plugin-stripper/src/lib/ast.ts b/packages/internals/src/lib/ast/astImports.ts similarity index 71% rename from packages/vite-plugin-stripper/src/lib/ast.ts rename to packages/internals/src/lib/ast/astImports.ts index b50fc3f4..9fcb0ceb 100644 --- a/packages/vite-plugin-stripper/src/lib/ast.ts +++ b/packages/internals/src/lib/ast/astImports.ts @@ -1,4 +1,4 @@ -import { parseTs, visit } from '@kitql/internals' +import { parse, visit, type ParseResult } from './ast.js' export type ImportInfo = { name: string @@ -12,9 +12,9 @@ export type UserInfo = { } export const imports = ( - code_or_program: string | ReturnType, -): { program: ReturnType; importsList: ImportInfo[] } => { - const program = typeof code_or_program === 'string' ? parseTs(code_or_program) : code_or_program + code_or_program: string | ParseResult, +): { program: ParseResult; importsList: ImportInfo[] } => { + const program = parse(code_or_program) const importsList: ImportInfo[] = [] visit(program, { @@ -72,15 +72,3 @@ export const imports = ( return { program, importsList } } - -export const usage = ( - code_or_program: string | ReturnType, - importsList: ImportInfo[], -): { program: ReturnType; importsList: ImportInfo[] } => { - const program = typeof code_or_program === 'string' ? parseTs(code_or_program) : code_or_program - if (importsList.length === 0) return { program, importsList: [] } - - const usageList: (ImportInfo & UserInfo)[] = [] - - return { program, importsList: [] } -} diff --git a/packages/internals/src/lib/index.ts b/packages/internals/src/lib/index.ts index f9a6a207..29bd9626 100644 --- a/packages/internals/src/lib/index.ts +++ b/packages/internals/src/lib/index.ts @@ -7,5 +7,16 @@ export { getRelativePackagePath, findFileOrUp, } from './fs/fs.js' -export { parseTs, extractHtmlElementAttr_Text, visit, prettyPrint, builders } from './ast/ast.js' -export type { Statement } from './ast/ast.js' + +export type { Statement, ParseResult } from './ast/ast.js' +export { + parse, + /** @deprecated Use `parse` instead */ + parseTs, + visit, + print, + /** @deprecated */ + builders, +} from './ast/ast.js' + +export { extractHtmlElementAttr_Text } from './ast/astHtml.js' diff --git a/packages/vite-plugin-kit-routes/src/lib/ast.ts b/packages/vite-plugin-kit-routes/src/lib/ast.ts index b7860c12..4f7c86bf 100644 --- a/packages/vite-plugin-kit-routes/src/lib/ast.ts +++ b/packages/vite-plugin-kit-routes/src/lib/ast.ts @@ -1,5 +1,5 @@ import { cyan, red, yellow } from '@kitql/helpers' -import { parseTs, read, visit } from '@kitql/internals' +import { parse, read, visit } from '@kitql/internals' import { log, routes_path } from './plugin.js' @@ -9,7 +9,7 @@ export const getMethodsOfServerFiles = (pathFile: string) => { const exportedNames: string[] = [] try { - const codeParsed = parseTs(code) + const codeParsed = parse(code) visit(codeParsed, { visitExportNamedDeclaration(path) { const declaration = path.node.declaration @@ -63,7 +63,7 @@ export const getActionsOfServerPages = (pathFile: string) => { let actions: string[] = [] try { - const codeParsed = parseTs(code) + const codeParsed = parse(code) visit(codeParsed, { visitExportNamedDeclaration(path) { // @ts-ignore diff --git a/packages/vite-plugin-stripper/package.json b/packages/vite-plugin-stripper/package.json index ae25723c..091deacf 100644 --- a/packages/vite-plugin-stripper/package.json +++ b/packages/vite-plugin-stripper/package.json @@ -34,7 +34,7 @@ "@sveltejs/kit": "catalog:sveltekit", "@sveltejs/package": "catalog:sveltekit", "@sveltejs/vite-plugin-svelte": "catalog:sveltekit", - "@vitest/ui": "catalog:", + "@vitest/ui": "catalog:testing", "publint": "catalog:lib-author-helper", "remult": "catalog:remult", "svelte": "catalog:svelte", diff --git a/packages/vite-plugin-stripper/src/lib/index.ts b/packages/vite-plugin-stripper/src/lib/index.ts index 992beaf7..a953503b 100644 --- a/packages/vite-plugin-stripper/src/lib/index.ts +++ b/packages/vite-plugin-stripper/src/lib/index.ts @@ -1,2 +1,2 @@ export type { ViteStripperOptions } from './plugin.js' -export { stripper } from './plugin.js' \ No newline at end of file +export { stripper } from './plugin.js' diff --git a/packages/vite-plugin-stripper/src/lib/nullifyImports.spec.ts b/packages/vite-plugin-stripper/src/lib/nullifyImports.spec.ts index 6a2a3e44..e53808d6 100644 --- a/packages/vite-plugin-stripper/src/lib/nullifyImports.spec.ts +++ b/packages/vite-plugin-stripper/src/lib/nullifyImports.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { nullifyImports } from './nullifyImports.js' +import { toInfoCode } from './testHelper.js' describe('package', () => { it('1 replace', async () => { @@ -25,7 +26,7 @@ describe('package', () => { const transformed = await nullifyImports(code, ['mongodb']) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "let ObjectId = null; @@ -74,7 +75,7 @@ describe('package', () => { const transformed = await nullifyImports(code, ['mongodb']) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "let ObjectId = null; let demo = null; diff --git a/packages/vite-plugin-stripper/src/lib/nullifyImports.ts b/packages/vite-plugin-stripper/src/lib/nullifyImports.ts index 109a9e60..56123336 100644 --- a/packages/vite-plugin-stripper/src/lib/nullifyImports.ts +++ b/packages/vite-plugin-stripper/src/lib/nullifyImports.ts @@ -1,8 +1,12 @@ -import { builders, parseTs, prettyPrint, visit } from '@kitql/internals' +import { builders, parse, visit } from '@kitql/internals' +import type { ParseResult } from '@kitql/internals' -export const nullifyImports = async (code: string, packages_to_strip: string[]) => { +export const nullifyImports = async ( + code_ast: string | ParseResult, + packages_to_strip: string[], +) => { try { - const ast = parseTs(code) + const ast = parse(code_ast) const packages_striped: string[] = [] @@ -36,10 +40,10 @@ export const nullifyImports = async (code: string, packages_to_strip: string[]) }) return { - code: prettyPrint(ast).code, + code_ast: ast, info: packages_striped.map((pkg) => `Nullify import from '${pkg}'`), } } catch (error) { - return { code, info: [] } + return { code_ast, info: [] } } } diff --git a/packages/vite-plugin-stripper/src/lib/plugin.ts b/packages/vite-plugin-stripper/src/lib/plugin.ts index 91d6e884..5696fce1 100644 --- a/packages/vite-plugin-stripper/src/lib/plugin.ts +++ b/packages/vite-plugin-stripper/src/lib/plugin.ts @@ -3,10 +3,9 @@ import type { PluginOption } from 'vite' import { watchAndRun } from 'vite-plugin-watch-and-run' import { gray, green, Log, yellow } from '@kitql/helpers' -import { getFilesUnder } from '@kitql/internals' +import { getFilesUnder, print, type ParseResult } from '@kitql/internals' import { nullifyImports } from './nullifyImports.js' -import { transformDecorator } from './transformDecorator.js' import { transformStrip, type StripConfig } from './transformStrip.js' import { transformWarningThrow, type WarningThrow } from './transformWarningThrow.js' @@ -151,53 +150,40 @@ export function stripper(options?: ViteStripperOptions): PluginOption { } const allInfos: string[] = [] - - if (options && options?.decorators && options.decorators.length > 0) { - const { info, ...rest } = await transformDecorator( - code, - options.decorators, - options.hard ?? false, - ) - - // Update the code for later transforms & return it - code = rest.code - allInfos.push(...info) - } + let code_ast: string | ParseResult = code if (options && options?.nullify && options.nullify.length > 0) { - const { info, ...rest } = await nullifyImports(code, options.nullify) + const { info, code_ast: transformed } = await nullifyImports(code_ast, options.nullify) // Update the code for later transforms & return it - code = rest.code + code_ast = transformed allInfos.push(...info) } if (options && options?.strip && options.strip.length > 0) { - const { info, ...rest } = await transformStrip(code, options.strip) + const { info, code_ast: transformed } = await transformStrip(code_ast, options.strip) // Update the code for later transforms & return it - code = rest.code + code_ast = transformed allInfos.push(...info) } - if (options?.debug && allInfos.length > 0) { - log.info( - `` + + if (allInfos.length > 0) { + const toRet = print(code_ast) + + if (options?.debug) { + log.info( `${gray('File:')} ${yellow(filepath)}\n` + - `${green('-----')}\n` + - `${code}` + - `\n${green(':::::')}\n` + - `${allInfos.join('\n')}` + - `\n${green('-----')}` + - ``, - ) - } + `${green('-----')}\n` + + `${toRet.code}` + + `\n${green(':::::')}\n` + + `${allInfos.join('\n')}` + + `\n${green('-----')}\n`, + ) + } - if (allInfos.length > 0) { - return { code, map: null } + return toRet } - - return }, }, diff --git a/packages/vite-plugin-stripper/src/lib/testHelper.ts b/packages/vite-plugin-stripper/src/lib/testHelper.ts new file mode 100644 index 00000000..86dee5a5 --- /dev/null +++ b/packages/vite-plugin-stripper/src/lib/testHelper.ts @@ -0,0 +1,15 @@ +import type { ParseResult } from '@kitql/internals' +import { print } from '@kitql/internals' + +export const toInfoCode = (input: { code_ast: string | ParseResult; info: string[] }) => { + if (typeof input.code_ast === 'string') { + return { + info: input.info, + code: input.code_ast, + } + } + return { + info: input.info, + code: print(input.code_ast!.program).code, + } +} diff --git a/packages/vite-plugin-stripper/src/lib/transformDecorator.spec.ts b/packages/vite-plugin-stripper/src/lib/transformDecorator.spec.ts deleted file mode 100644 index 2cbdf485..00000000 --- a/packages/vite-plugin-stripper/src/lib/transformDecorator.spec.ts +++ /dev/null @@ -1,542 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import { transformDecorator } from './transformDecorator.js' - -describe('decorator', () => { - it('should empty @BackendMethod and clean imports', async () => { - const code = `import { Allow, BackendMethod, remult } from "remult"; -import { Task } from "./task"; -import { AUTH_SECRET } from "$env/static/private"; - -export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - @BackendMethod({ allowed: Allow.authenticated }) - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - - const taskRepo = remult.repo(Task); - for (const task of await taskRepo.find()) { - await taskRepo.save({ ...task, completed }); - } - } - - @BackendMethod({ allowed: Allow.authenticated }) - static async Yop(completed: boolean) { - // console.log("AUTH_SECRET", AUTH_SECRET); - - const taskRepo = remult.repo(Task); - for (const task of await taskRepo.find()) { - await taskRepo.save({ ...task, completed }); - } - } -} - ` - - let transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { BackendMethod, Allow, remult } from "remult"; - import { Task } from "./task"; - - export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - @BackendMethod({ - allowed: Allow.authenticated - }) - static async setAllCompleted(completed) {} - - @BackendMethod({ - allowed: Allow.authenticated - }) - static async Yop(completed) {} - }", - "info": [ - "Striped: ["TasksController","BackendMethod","setAllCompleted"]", - "Striped: ["TasksController","BackendMethod","Yop"]", - "Removed: 'AUTH_SECRET' from '$env/static/private'", - ], - } - `) - - transformed = await transformDecorator(code, ['BackendMethod'], true) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { BackendMethod } from 'remult' - - export class TasksController { - @BackendMethod({}) - static async setAllCompleted() {} - @BackendMethod({}) - static async Yop() {} - }", - "info": [ - "Striped: ["TasksController","BackendMethod","setAllCompleted"]", - "Striped: ["TasksController","BackendMethod","Yop"]", - "Removed: 'AUTH_SECRET' from '$env/static/private'", - ], - } - `) - }) - - it('should not crash if there is an error in the original file', async () => { - const code = `import { Allow, BackendMethod, remult } from "remult"; -import { Task } from "./task"; -import { AUTH_SECRET } from "$env/static/private"; - -export class TasksController { - @BackendMethod({ allowed: Allow.authenticated }) - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - //} LEAVE THIS ERROR TO SIMULATE A WRONG PARSED FILE -} - ` - - const transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Allow, BackendMethod, remult } from "remult"; - import { Task } from "./task"; - import { AUTH_SECRET } from "$env/static/private"; - - export class TasksController { - @BackendMethod({ allowed: Allow.authenticated }) - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - //} LEAVE THIS ERROR TO SIMULATE A WRONG PARSED FILE - } - ", - "info": [], - } - `) - }) - - it('should not do anything as there is no @BackendMethod', async () => { - const code = `import { Allow, BackendMethod, remult } from "remult"; -import { Task } from "./task"; -import { AUTH_SECRET } from "$env/static/private"; - -export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - - const taskRepo = remult.repo(Task); - for (const task of await taskRepo.find()) { - await taskRepo.save({ ...task, completed }); - } - } -} - ` - - let transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Allow, BackendMethod, remult } from "remult"; - import { Task } from "./task"; - import { AUTH_SECRET } from "$env/static/private"; - - export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - const taskRepo = remult.repo(Task); - - for (const task of await taskRepo.find()) { - await taskRepo.save({ - ...task, - completed - }); - } - } - }", - "info": [], - } - `) - - transformed = await transformDecorator(code, ['BackendMethod'], true) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Allow, BackendMethod, remult } from "remult"; - import { Task } from "./task"; - import { AUTH_SECRET } from "$env/static/private"; - - export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - static async setAllCompleted(completed: boolean) { - console.log("AUTH_SECRET", AUTH_SECRET); - const taskRepo = remult.repo(Task); - - for (const task of await taskRepo.find()) { - await taskRepo.save({ - ...task, - completed - }); - } - } - }", - "info": [], - } - `) - }) - - it('should strip also unused methods', async () => { - const code = `import { TOP_SECRET, TOP_SECRET_NOT_USED } from '$env/static/private'; - import { stry0 } from '@kitql/helper'; - import { BackendMethod, Entity, Fields, remult } from 'remult'; - - @Entity() - export class Ent { - @Fields.uuid() - id!: string; - } - - const getInfo = () => { - const client = {} - - console.log(TOP_SECRET) - - return client; - }; - - export class EntController { - @BackendMethod({ allowed: false }) - static async init(hello: string) { - const client = getInfo(); - - // Do a lot of things here - } - } - ` - - let transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Entity, Fields, BackendMethod } from "remult"; - import { TOP_SECRET } from "$env/static/private"; - - @Entity() - export class Ent { - @Fields.uuid() - id!: string; - } - - const getInfo = () => { - const client = {}; - console.log(TOP_SECRET); - return client; - }; - - export class EntController { - @BackendMethod({ - allowed: false - }) - static async init(hello) {} - }", - "info": [ - "Striped: ["EntController","BackendMethod","init"]", - "Removed: 'TOP_SECRET_NOT_USED' from '$env/static/private'", - "Removed: 'stry0' from '@kitql/helper'", - "Removed: 'remult' from 'remult'", - ], - } - `) - - transformed = await transformDecorator(code, ['BackendMethod'], true) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { BackendMethod } from 'remult' - - export class EntController { - @BackendMethod({}) - static async init() {} - }", - "info": [ - "Striped: ["EntController","BackendMethod","init"]", - "Removed: 'TOP_SECRET_NOT_USED' from '$env/static/private'", - "Removed: 'stry0' from '@kitql/helper'", - "Removed: 'remult' from 'remult'", - ], - } - `) - }) - - it('should strip just the right things', async () => { - const code = `import { Allow, BackendMethod, Entity, Fields, Validators } from 'remult' - - @Entity('userstest', { - allowApiCrud: Allow.authenticated, - }) - export class User2 { - @Fields.uuid() - id = '' - - @Fields.string({ - validate: [Validators.required, Validators.uniqueOnBackend], - }) - email = '' - - @BackendMethod({ allowed: Allow.everyone }) - async testMethod() { - console.log('hello') - } - } - ` - - const transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Entity, Allow, Fields, Validators, BackendMethod } from "remult"; - - @Entity("userstest", { - allowApiCrud: Allow.authenticated - }) - export class User2 { - @Fields.uuid() - id = ""; - - @Fields.string({ - validate: [Validators.required, Validators.uniqueOnBackend] - }) - email = ""; - - @BackendMethod({ - allowed: Allow.everyone - }) - async testMethod() {} - }", - "info": [ - "Striped: ["User2","BackendMethod","testMethod"]", - ], - } - `) - }) - - it('should strip unused stuff when decorator', async () => { - const code = `import { Allow, BackendMethod, Entity, Fields, Validators } from 'remult' - - @Entity('userstest', { - allowApiCrud: Allow.authenticated, - }) - export class User2 { - @Fields.uuid() - id = '' - - @Fields.string({}) - email = '' - - @BackendMethod({ allowed: Allow.everyone }) - async testMethod() { - console.log('hello') - } - } - ` - - const transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Entity, Allow, Fields, BackendMethod } from "remult"; - - @Entity("userstest", { - allowApiCrud: Allow.authenticated - }) - export class User2 { - @Fields.uuid() - id = ""; - - @Fields.string({}) - email = ""; - - @BackendMethod({ - allowed: Allow.everyone - }) - async testMethod() {} - }", - "info": [ - "Striped: ["User2","BackendMethod","testMethod"]", - "Removed: 'Validators' from 'remult'", - ], - } - `) - }) - - it('should strip imports that are in the BackendMethod', async () => { - const code = `import { Allow, BackendMethod, Entity, Fields, Validators } from 'remult' - - @Entity('userstest', { - allowApiCrud: Allow.authenticated, - }) - export class User2 { - @Fields.uuid() - id = '' - - @Fields.string({}) - email = '' - - @BackendMethod({ allowed: Allow.everyone }) - async testMethod() { - console.log('hello', Validators.required) - } - } - ` - - const transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Entity, Allow, Fields, BackendMethod } from "remult"; - - @Entity("userstest", { - allowApiCrud: Allow.authenticated - }) - export class User2 { - @Fields.uuid() - id = ""; - - @Fields.string({}) - email = ""; - - @BackendMethod({ - allowed: Allow.everyone - }) - async testMethod() {} - }", - "info": [ - "Striped: ["User2","BackendMethod","testMethod"]", - "Removed: 'Validators' from 'remult'", - ], - } - `) - }) - - it('should NOT strip imports that are in both in BackendMethod and not in', async () => { - const code = `import { Allow, BackendMethod, Entity, Fields, Validators } from 'remult' - - @Entity('userstest', { - allowApiCrud: Allow.authenticated, - }) - export class User2 { - @Fields.uuid() - id = '' - - @Fields.string({ - validate: [Validators.required, Validators.uniqueOnBackend], - }) - email = '' - - @BackendMethod({ allowed: Allow.everyone }) - async testMethod() { - console.log('hello', Validators.required) - } - } - ` - - const transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { Entity, Allow, Fields, Validators, BackendMethod } from "remult"; - - @Entity("userstest", { - allowApiCrud: Allow.authenticated - }) - export class User2 { - @Fields.uuid() - id = ""; - - @Fields.string({ - validate: [Validators.required, Validators.uniqueOnBackend] - }) - email = ""; - - @BackendMethod({ - allowed: Allow.everyone - }) - async testMethod() {} - }", - "info": [ - "Striped: ["User2","BackendMethod","testMethod"]", - ], - } - `) - }) - - it('should strip import types', async () => { - const code = `import { AUTH_SECRET } from '$env/static/private' - import { BackendMethod, type Allowed, remult } from 'remult' - - export class ActionsController { - @BackendMethod({ - // Only unauthenticated users can call this method - allowed: () => remult.user === undefined, - }) - static async read(info: Allowed) { - console.log('AUTH_SECRET', AUTH_SECRET) - return AUTH_SECRET + ' ' + info - } - } - - ` - - let transformed = await transformDecorator(code, ['BackendMethod'], false) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { BackendMethod, remult } from "remult"; - - export class ActionsController { - @BackendMethod({ - allowed: () => remult.user === undefined - }) - static async read(info) {} - }", - "info": [ - "Striped: ["ActionsController","BackendMethod","read"]", - "Removed: 'AUTH_SECRET' from '$env/static/private'", - "Removed: 'Allowed' from 'remult'", - ], - } - `) - - transformed = await transformDecorator(code, ['BackendMethod'], true) - - expect(transformed).toMatchInlineSnapshot(` - { - "code": "import { BackendMethod } from 'remult' - - export class ActionsController { - @BackendMethod({}) - static async read() {} - }", - "info": [ - "Striped: ["ActionsController","BackendMethod","read"]", - "Removed: 'AUTH_SECRET' from '$env/static/private'", - "Removed: 'Allowed' from 'remult'", - ], - } - `) - }) -}) diff --git a/packages/vite-plugin-stripper/src/lib/transformDecorator.ts b/packages/vite-plugin-stripper/src/lib/transformDecorator.ts deleted file mode 100644 index 2037ae44..00000000 --- a/packages/vite-plugin-stripper/src/lib/transformDecorator.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { parseTs, prettyPrint, visit } from '@kitql/internals' -import type { Statement } from '@kitql/internals' - -export const removeUnusedImports = async (code: string) => { - try { - const program = parseTs(code) - - const usedIdentifiers = new Set() - const originalImports = new Map() - - // Step 1: Remove all global imports and store them - const newBody: Statement[] = [] - program.body.forEach((node) => { - if (node.type === 'ImportDeclaration') { - ;(node.specifiers ?? []).forEach((specifier) => { - if (specifier.type === 'ImportSpecifier') { - const name = - specifier.imported && specifier.imported.type === 'Identifier' - ? specifier.imported.name - : specifier.local?.name - if (!originalImports.has(name)) { - originalImports.set(name, node.source.value) - } - } - }) - } else { - newBody.push(node) - } - }) - // @ts-ignore - program.body = newBody - - // Step 2: List all identifiers used in the code - visit(program, { - visitIdentifier(path: any) { - // Let's not add identifiers from import specifiers - if (path.parentPath.value.type !== 'ImportSpecifier') { - usedIdentifiers.add(path.node.name) - } - - this.traverse(path) - }, - - visitClassDeclaration(path: any) { - // Capture identifiers in class decorators - // @ts-ignore - ;(path.node.decorators || []).forEach((decorator) => { - extractIdentifiersFromExpression(decorator.expression, usedIdentifiers) - }) - - // Capture identifiers in class methods and properties - path.node.body.body.forEach((element: any) => { - if (element.type === 'ClassMethod' || element.type === 'ClassProperty') { - // Capture identifiers in element decorators - // @ts-ignore - ;(element.decorators || []).forEach((decorator: any) => { - extractIdentifiersFromExpression(decorator.expression, usedIdentifiers) - }) - } - }) - - this.traverse(path) - }, - }) - - let removed = Array.from(originalImports) - - // Step 3: Add back necessary imports - const necessaryImports: Statement[] = [] - usedIdentifiers.forEach((identifier) => { - if (originalImports.has(identifier)) { - const source = originalImports.get(identifier) - removed = removed.filter(([id, src]) => !(id === identifier && src === source)) - // @ts-ignore - const found = necessaryImports.find((importDecl) => importDecl.source.value === source) - if (found) { - // @ts-ignore - found.specifiers.push({ - type: 'ImportSpecifier', - imported: { type: 'Identifier', name: identifier }, - local: { type: 'Identifier', name: identifier }, - }) - } else { - necessaryImports.push({ - type: 'ImportDeclaration', - // @ts-ignore - specifiers: [ - { - type: 'ImportSpecifier', - imported: { type: 'Identifier', name: identifier }, - local: { type: 'Identifier', name: identifier }, - }, - ], - source: { type: 'StringLiteral', value: source }, - }) - } - } - }) - - // @ts-ignore - program.body.unshift(...necessaryImports) - - return { - code: prettyPrint(program).code, - info: removed.map(([id, src]) => `Removed: '${id}' from '${src}'`), - } - } catch (error) { - return { code, info: [] } - } -} - -export const transformDecorator = async ( - code: string, - decorators_to_strip: string[], - hard: boolean, -) => { - try { - const program = parseTs(code) - - let currentClassName = '' // Variable to hold the current class name - const decorators_striped: { decorator: string; functionName: string; className: string }[] = [] - - // Empty functions with one of the decorators. (ex @BackendMethod decorator) - visit(program, { - visitClassDeclaration(path: any) { - // @ts-ignore - currentClassName = path.node.id.name - this.traverse(path) - }, - visitFunction(path: any) { - // @ts-ignore - const decorators: any[] = path.node.decorators || [] - let foundDecorator = false - - let functionName: string - // Check if the function is a standalone function or a method in a class - if (path.node.id && path.node.id.name) { - // Standalone function - functionName = typeof path.node.id.name === 'string' ? path.node.id.name : 'IdentifierKind' - // @ts-ignore - } else if (path.node.key && path.node.key.name) { - // @ts-ignore - functionName = path.node.key.name - } - - // @ts-ignore - path.node.decorators = decorators.filter((decorator) => { - if ( - decorator.expression.callee && - decorators_to_strip.includes(decorator.expression.callee.name) - ) { - foundDecorator = true - - // Push both the decorator name and the associated function name - decorators_striped.push({ - className: currentClassName, - decorator: decorator.expression.callee.name, - functionName: functionName ?? '???', - }) - - // We actually need to keep the decorator - // return false; - } - return true - }) - - // If one of the decorators was found, empty the function body and remove types - if (foundDecorator) { - path.node.body.body = [] - - // Remove the return type of the function - if (path.node.returnType) { - delete path.node.returnType - } - - // Remove the types of all parameters - path.node.params.forEach((param: any) => { - // @ts-ignore - if (param.typeAnnotation) { - // @ts-ignore - delete param.typeAnnotation - } - }) - } - - this.traverse(path) - }, - }) - - const res = prettyPrint(program, {}) - const info = decorators_striped.map( - (decorator) => `Striped: ${JSON.stringify(Object.values(decorator))}`, - ) - - if (decorators_striped.length > 0) { - const { code, info: newInfo } = await removeUnusedImports(res.code) - res.code = code - info.push(...newInfo) - } - - if (decorators_striped.length > 0 && hard) { - // decorators_striped group by className with valid typescript - const groupedByClassName = decorators_striped.reduce( - ( - acc: Record, - item, - ) => { - if (!acc[item.className]) { - acc[item.className] = [] - } - acc[item.className].push(item) - return acc - }, - {}, - ) - - res.code = `import { BackendMethod } from 'remult' - -${Object.entries(groupedByClassName).map(([className, decorators]) => { - return `export class ${className} {${decorators - .map( - (c) => `\n @BackendMethod({}) - static async ${c.functionName}() {}`, - ) - .join('')} -}` -})}` - } - - return { ...res, info } - } catch (error) { - // if anything happens, just return the original code - return { code, info: [] } - } -} - -// Helper function to extract identifiers from an expression -// @ts-ignore -function extractIdentifiersFromExpression(expression: any, identifierSet: Set) { - if (!expression) return - - switch (expression.type) { - case 'Identifier': - identifierSet.add(expression.name) - break - case 'MemberExpression': - extractIdentifiersFromExpression(expression.object, identifierSet) - extractIdentifiersFromExpression(expression.property, identifierSet) - break - case 'CallExpression': - extractIdentifiersFromExpression(expression.callee, identifierSet) - expression.arguments.forEach((arg: any) => extractIdentifiersFromExpression(arg, identifierSet)) - break - case 'ArrayExpression': - expression.elements.forEach((element: any) => - extractIdentifiersFromExpression(element, identifierSet), - ) - break - case 'ObjectExpression': - expression.properties.forEach((prop: any) => { - if (prop.type === 'SpreadElement') { - extractIdentifiersFromExpression(prop.argument, identifierSet) - } else if (prop.value) { - extractIdentifiersFromExpression(prop.value, identifierSet) - } - }) - break - case 'VariableDeclarator': - if (expression.id && expression.id.type === 'Identifier') { - identifierSet.add(expression.id.name) - } - if (expression.init) { - extractIdentifiersFromExpression(expression.init, identifierSet) - } - break - // Add cases for other types as needed - } -} diff --git a/packages/vite-plugin-stripper/src/lib/transformStrip.spec.ts b/packages/vite-plugin-stripper/src/lib/transformStrip.spec.ts index 84aa7a1e..8d9970ea 100644 --- a/packages/vite-plugin-stripper/src/lib/transformStrip.spec.ts +++ b/packages/vite-plugin-stripper/src/lib/transformStrip.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { nullifyImports } from './nullifyImports.js' +import { toInfoCode } from './testHelper.js' import { transformStrip } from './transformStrip.js' describe('transformStrip (init)', () => { @@ -33,7 +34,7 @@ export class ActionsController { ` const data = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(data).toMatchInlineSnapshot(` + expect(toInfoCode(data)).toMatchInlineSnapshot(` { "code": "import { BackendMethod, remult, type Allowed } from "remult"; import { performance } from "perf_hooks"; @@ -117,48 +118,3206 @@ export class TasksController { expect(transformed).toMatchInlineSnapshot(` { - "code": "import { Allow, BackendMethod, remult } from "remult"; - import { Task } from "./task"; - import { AUTH_SECRET } from "$env/static/private"; - - export class TasksController { - static async yop1(completed: boolean) { - const taskRepo = remult.repo(Task); - } - - @BackendMethod({ - allowed: Allow.authenticated - }) - static async setAllCompleted(completed: boolean) { - if (import.meta.env.SSR) { - console.log("AUTH_SECRET", AUTH_SECRET); - const taskRepo = remult.repo(Task); - - for (const task of await taskRepo.find()) { - await taskRepo.save({ - ...task, - completed - }); - } - } - } - - @BackendMethod({ - allowed: Allow.authenticated - }) - static async Yop(completed: boolean) { - if (import.meta.env.SSR) { - const taskRepo = remult.repo(Task); - - for (const task of await taskRepo.find()) { - await taskRepo.save({ - ...task, - completed - }); - } - } - } - }", + "code_ast": Node { + "comments": [ + { + "end": 673, + "loc": SourceLocation { + "end": Position { + "column": 45, + "index": 673, + "line": 22, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 630, + "line": 22, + }, + }, + "start": 630, + "type": "CommentLine", + "value": " console.log("AUTH_SECRET", AUTH_SECRET);", + }, + ], + "end": 817, + "errors": [], + "loc": SourceLocation { + "end": Position { + "column": 1, + "index": 817, + "line": 30, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 0, + "line": 1, + }, + }, + "name": null, + "program": Node { + "body": [ + Node { + "assertions": [], + "end": 54, + "importKind": "value", + "loc": SourceLocation { + "end": Position { + "column": 54, + "index": 54, + "line": 1, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 0, + "line": 1, + }, + }, + "source": Node { + "end": 53, + "extra": { + "raw": ""remult"", + "rawValue": "remult", + }, + "loc": SourceLocation { + "end": Position { + "column": 53, + "index": 53, + "line": 1, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 45, + "index": 45, + "line": 1, + }, + }, + "start": 45, + "type": "StringLiteral", + "value": "remult", + }, + "specifiers": [ + Node { + "end": 14, + "id": null, + "importKind": "value", + "imported": Node { + "end": 14, + "loc": SourceLocation { + "end": Position { + "column": 14, + "index": 14, + "line": 1, + }, + "filename": undefined, + "identifierName": "Allow", + "start": Position { + "column": 9, + "index": 9, + "line": 1, + }, + }, + "name": "Allow", + "optional": false, + "start": 9, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 14, + "index": 14, + "line": 1, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 9, + "line": 1, + }, + }, + "local": Node { + "end": 14, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 14, + "index": 14, + "line": 1, + }, + "filename": undefined, + "identifierName": "Allow", + "start": Position { + "column": 9, + "index": 9, + "line": 1, + }, + }, + "name": "Allow", + "optional": false, + "range": undefined, + "start": 9, + "type": "Identifier", + "typeAnnotation": null, + }, + "name": null, + "start": 9, + "type": "ImportSpecifier", + }, + Node { + "end": 29, + "id": null, + "importKind": "value", + "imported": Node { + "end": 29, + "loc": SourceLocation { + "end": Position { + "column": 29, + "index": 29, + "line": 1, + }, + "filename": undefined, + "identifierName": "BackendMethod", + "start": Position { + "column": 16, + "index": 16, + "line": 1, + }, + }, + "name": "BackendMethod", + "optional": false, + "start": 16, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 29, + "index": 29, + "line": 1, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 16, + "index": 16, + "line": 1, + }, + }, + "local": Node { + "end": 29, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 29, + "index": 29, + "line": 1, + }, + "filename": undefined, + "identifierName": "BackendMethod", + "start": Position { + "column": 16, + "index": 16, + "line": 1, + }, + }, + "name": "BackendMethod", + "optional": false, + "range": undefined, + "start": 16, + "type": "Identifier", + "typeAnnotation": null, + }, + "name": null, + "start": 16, + "type": "ImportSpecifier", + }, + Node { + "end": 37, + "id": null, + "importKind": "value", + "imported": Node { + "end": 37, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 37, + "line": 1, + }, + "filename": undefined, + "identifierName": "remult", + "start": Position { + "column": 31, + "index": 31, + "line": 1, + }, + }, + "name": "remult", + "optional": false, + "start": 31, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 37, + "line": 1, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 31, + "index": 31, + "line": 1, + }, + }, + "local": Node { + "end": 37, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 37, + "line": 1, + }, + "filename": undefined, + "identifierName": "remult", + "start": Position { + "column": 31, + "index": 31, + "line": 1, + }, + }, + "name": "remult", + "optional": false, + "range": undefined, + "start": 31, + "type": "Identifier", + "typeAnnotation": null, + }, + "name": null, + "start": 31, + "type": "ImportSpecifier", + }, + ], + "start": 0, + "type": "ImportDeclaration", + }, + Node { + "assertions": [], + "end": 85, + "importKind": "value", + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 85, + "line": 2, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 55, + "line": 2, + }, + }, + "source": Node { + "end": 84, + "extra": { + "raw": ""./task"", + "rawValue": "./task", + }, + "loc": SourceLocation { + "end": Position { + "column": 29, + "index": 84, + "line": 2, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 21, + "index": 76, + "line": 2, + }, + }, + "start": 76, + "type": "StringLiteral", + "value": "./task", + }, + "specifiers": [ + Node { + "end": 68, + "id": null, + "importKind": "value", + "imported": Node { + "end": 68, + "loc": SourceLocation { + "end": Position { + "column": 13, + "index": 68, + "line": 2, + }, + "filename": undefined, + "identifierName": "Task", + "start": Position { + "column": 9, + "index": 64, + "line": 2, + }, + }, + "name": "Task", + "optional": false, + "start": 64, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 13, + "index": 68, + "line": 2, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 64, + "line": 2, + }, + }, + "local": Node { + "end": 68, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 13, + "index": 68, + "line": 2, + }, + "filename": undefined, + "identifierName": "Task", + "start": Position { + "column": 9, + "index": 64, + "line": 2, + }, + }, + "name": "Task", + "optional": false, + "range": undefined, + "start": 64, + "type": "Identifier", + "typeAnnotation": null, + }, + "name": null, + "start": 64, + "type": "ImportSpecifier", + }, + ], + "start": 55, + "type": "ImportDeclaration", + }, + Node { + "assertions": [], + "end": 136, + "importKind": "value", + "loc": SourceLocation { + "end": Position { + "column": 50, + "index": 136, + "line": 3, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 86, + "line": 3, + }, + }, + "source": Node { + "end": 135, + "extra": { + "raw": ""$env/static/private"", + "rawValue": "$env/static/private", + }, + "loc": SourceLocation { + "end": Position { + "column": 49, + "index": 135, + "line": 3, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 28, + "index": 114, + "line": 3, + }, + }, + "start": 114, + "type": "StringLiteral", + "value": "$env/static/private", + }, + "specifiers": [ + Node { + "end": 106, + "id": null, + "importKind": "value", + "imported": Node { + "end": 106, + "loc": SourceLocation { + "end": Position { + "column": 20, + "index": 106, + "line": 3, + }, + "filename": undefined, + "identifierName": "AUTH_SECRET", + "start": Position { + "column": 9, + "index": 95, + "line": 3, + }, + }, + "name": "AUTH_SECRET", + "optional": false, + "start": 95, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 20, + "index": 106, + "line": 3, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 95, + "line": 3, + }, + }, + "local": Node { + "end": 106, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 20, + "index": 106, + "line": 3, + }, + "filename": undefined, + "identifierName": "AUTH_SECRET", + "start": Position { + "column": 9, + "index": 95, + "line": 3, + }, + }, + "name": "AUTH_SECRET", + "optional": false, + "range": undefined, + "start": 95, + "type": "Identifier", + "typeAnnotation": null, + }, + "name": null, + "start": 95, + "type": "ImportSpecifier", + }, + ], + "start": 86, + "type": "ImportDeclaration", + }, + Node { + "assertions": [], + "declaration": Node { + "body": Node { + "body": [ + Node { + "abstract": false, + "access": null, + "accessibility": null, + "async": true, + "body": Node { + "body": [ + Node { + "declarations": [ + Node { + "end": 246, + "id": Node { + "end": 226, + "loc": SourceLocation { + "end": Position { + "column": 16, + "index": 226, + "line": 7, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 8, + "index": 218, + "line": 7, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 218, + "type": "Identifier", + "typeAnnotation": null, + }, + "init": Node { + "arguments": [ + Node { + "end": 245, + "loc": SourceLocation { + "end": Position { + "column": 35, + "index": 245, + "line": 7, + }, + "filename": undefined, + "identifierName": "Task", + "start": Position { + "column": 31, + "index": 241, + "line": 7, + }, + }, + "name": "Task", + "optional": false, + "start": 241, + "type": "Identifier", + "typeAnnotation": null, + }, + ], + "callee": Node { + "computed": false, + "end": 240, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 240, + "line": 7, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 229, + "line": 7, + }, + }, + "object": Node { + "end": 235, + "loc": SourceLocation { + "end": Position { + "column": 25, + "index": 235, + "line": 7, + }, + "filename": undefined, + "identifierName": "remult", + "start": Position { + "column": 19, + "index": 229, + "line": 7, + }, + }, + "name": "remult", + "optional": false, + "start": 229, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 240, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 240, + "line": 7, + }, + "filename": undefined, + "identifierName": "repo", + "start": Position { + "column": 26, + "index": 236, + "line": 7, + }, + }, + "name": "repo", + "optional": false, + "start": 236, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 229, + "type": "MemberExpression", + }, + "end": 246, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 246, + "line": 7, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 229, + "line": 7, + }, + }, + "optional": false, + "start": 229, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 246, + "line": 7, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 8, + "index": 218, + "line": 7, + }, + }, + "start": 218, + "type": "VariableDeclarator", + }, + ], + "end": 247, + "kind": "const", + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 247, + "line": 7, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 212, + "line": 7, + }, + }, + "start": 212, + "type": "VariableDeclaration", + }, + ], + "directives": [], + "end": 250, + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 250, + "line": 8, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 39, + "index": 208, + "line": 6, + }, + }, + "start": 208, + "type": "BlockStatement", + }, + "computed": false, + "decorators": null, + "defaults": [], + "definite": false, + "end": 250, + "expression": false, + "generator": false, + "id": null, + "key": Node { + "end": 187, + "loc": SourceLocation { + "end": Position { + "column": 18, + "index": 187, + "line": 6, + }, + "filename": undefined, + "identifierName": "yop1", + "start": Position { + "column": 14, + "index": 183, + "line": 6, + }, + }, + "name": "yop1", + "optional": false, + "start": 183, + "type": "Identifier", + "typeAnnotation": null, + }, + "kind": "method", + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 250, + "line": 8, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 1, + "index": 170, + "line": 6, + }, + }, + "optional": false, + "override": false, + "params": [ + Node { + "end": 206, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 206, + "line": 6, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 19, + "index": 188, + "line": 6, + }, + }, + "name": "completed", + "optional": false, + "start": 188, + "type": "Identifier", + "typeAnnotation": Node { + "end": 206, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 206, + "line": 6, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 28, + "index": 197, + "line": 6, + }, + }, + "start": 197, + "type": "TSTypeAnnotation", + "typeAnnotation": Node { + "end": 206, + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 206, + "line": 6, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 30, + "index": 199, + "line": 6, + }, + }, + "start": 199, + "type": "TSBooleanKeyword", + }, + }, + }, + ], + "predicate": null, + "readonly": false, + "rest": null, + "returnType": null, + "start": 170, + "static": true, + "type": "ClassMethod", + "typeParameters": null, + }, + Node { + "abstract": false, + "access": null, + "accessibility": null, + "async": true, + "body": Node { + "body": [ + { + "alternate": null, + "consequent": { + "body": [ + Node { + "end": 396, + "expression": Node { + "arguments": [ + Node { + "end": 381, + "extra": { + "raw": ""AUTH_SECRET"", + "rawValue": "AUTH_SECRET", + }, + "loc": SourceLocation { + "end": Position { + "column": 27, + "index": 381, + "line": 12, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 14, + "index": 368, + "line": 12, + }, + }, + "start": 368, + "type": "StringLiteral", + "value": "AUTH_SECRET", + }, + Node { + "end": 394, + "loc": SourceLocation { + "end": Position { + "column": 40, + "index": 394, + "line": 12, + }, + "filename": undefined, + "identifierName": "AUTH_SECRET", + "start": Position { + "column": 29, + "index": 383, + "line": 12, + }, + }, + "name": "AUTH_SECRET", + "optional": false, + "start": 383, + "type": "Identifier", + "typeAnnotation": null, + }, + ], + "callee": Node { + "computed": false, + "end": 367, + "loc": SourceLocation { + "end": Position { + "column": 13, + "index": 367, + "line": 12, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 356, + "line": 12, + }, + }, + "object": Node { + "end": 363, + "loc": SourceLocation { + "end": Position { + "column": 9, + "index": 363, + "line": 12, + }, + "filename": undefined, + "identifierName": "console", + "start": Position { + "column": 2, + "index": 356, + "line": 12, + }, + }, + "name": "console", + "optional": false, + "start": 356, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 367, + "loc": SourceLocation { + "end": Position { + "column": 13, + "index": 367, + "line": 12, + }, + "filename": undefined, + "identifierName": "log", + "start": Position { + "column": 10, + "index": 364, + "line": 12, + }, + }, + "name": "log", + "optional": false, + "start": 364, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 356, + "type": "MemberExpression", + }, + "end": 395, + "loc": SourceLocation { + "end": Position { + "column": 41, + "index": 395, + "line": 12, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 356, + "line": 12, + }, + }, + "optional": false, + "start": 356, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 42, + "index": 396, + "line": 12, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 356, + "line": 12, + }, + }, + "start": 356, + "type": "ExpressionStatement", + }, + Node { + "declarations": [ + Node { + "end": 434, + "id": Node { + "end": 414, + "loc": SourceLocation { + "end": Position { + "column": 16, + "index": 414, + "line": 14, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 8, + "index": 406, + "line": 14, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 406, + "type": "Identifier", + "typeAnnotation": null, + }, + "init": Node { + "arguments": [ + Node { + "end": 433, + "loc": SourceLocation { + "end": Position { + "column": 35, + "index": 433, + "line": 14, + }, + "filename": undefined, + "identifierName": "Task", + "start": Position { + "column": 31, + "index": 429, + "line": 14, + }, + }, + "name": "Task", + "optional": false, + "start": 429, + "type": "Identifier", + "typeAnnotation": null, + }, + ], + "callee": Node { + "computed": false, + "end": 428, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 428, + "line": 14, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 417, + "line": 14, + }, + }, + "object": Node { + "end": 423, + "loc": SourceLocation { + "end": Position { + "column": 25, + "index": 423, + "line": 14, + }, + "filename": undefined, + "identifierName": "remult", + "start": Position { + "column": 19, + "index": 417, + "line": 14, + }, + }, + "name": "remult", + "optional": false, + "start": 417, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 428, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 428, + "line": 14, + }, + "filename": undefined, + "identifierName": "repo", + "start": Position { + "column": 26, + "index": 424, + "line": 14, + }, + }, + "name": "repo", + "optional": false, + "start": 424, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 417, + "type": "MemberExpression", + }, + "end": 434, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 434, + "line": 14, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 417, + "line": 14, + }, + }, + "optional": false, + "start": 417, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 434, + "line": 14, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 8, + "index": 406, + "line": 14, + }, + }, + "start": 406, + "type": "VariableDeclarator", + }, + ], + "end": 435, + "kind": "const", + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 435, + "line": 14, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 400, + "line": 14, + }, + }, + "start": 400, + "type": "VariableDeclaration", + }, + Node { + "await": false, + "body": Node { + "body": [ + Node { + "end": 529, + "expression": Node { + "all": false, + "argument": Node { + "arguments": [ + Node { + "end": 527, + "loc": SourceLocation { + "end": Position { + "column": 45, + "index": 527, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 23, + "index": 505, + "line": 16, + }, + }, + "properties": [ + Node { + "argument": Node { + "end": 514, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 514, + "line": 16, + }, + "filename": undefined, + "identifierName": "task", + "start": Position { + "column": 28, + "index": 510, + "line": 16, + }, + }, + "name": "task", + "optional": false, + "start": 510, + "type": "Identifier", + "typeAnnotation": null, + }, + "end": 514, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 514, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 25, + "index": 507, + "line": 16, + }, + }, + "start": 507, + "type": "SpreadElement", + }, + Node { + "accessibility": null, + "computed": false, + "end": 525, + "extra": { + "shorthand": true, + }, + "key": Node { + "end": 525, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 525, + "line": 16, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 34, + "index": 516, + "line": 16, + }, + }, + "name": "completed", + "optional": false, + "start": 516, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 525, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 34, + "index": 516, + "line": 16, + }, + }, + "method": false, + "shorthand": true, + "start": 516, + "type": "ObjectProperty", + "value": Node { + "end": 525, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 525, + "line": 16, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 34, + "index": 516, + "line": 16, + }, + }, + "name": "completed", + "optional": false, + "range": undefined, + "start": 516, + "type": "Identifier", + "typeAnnotation": null, + }, + }, + ], + "start": 505, + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "end": 504, + "loc": SourceLocation { + "end": Position { + "column": 22, + "index": 504, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 491, + "line": 16, + }, + }, + "object": Node { + "end": 499, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 499, + "line": 16, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 9, + "index": 491, + "line": 16, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 491, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 504, + "loc": SourceLocation { + "end": Position { + "column": 22, + "index": 504, + "line": 16, + }, + "filename": undefined, + "identifierName": "save", + "start": Position { + "column": 18, + "index": 500, + "line": 16, + }, + }, + "name": "save", + "optional": false, + "start": 500, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 491, + "type": "MemberExpression", + }, + "end": 528, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 528, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 491, + "line": 16, + }, + }, + "optional": false, + "start": 491, + "type": "CallExpression", + "typeArguments": null, + }, + "end": 528, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 528, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 3, + "index": 485, + "line": 16, + }, + }, + "start": 485, + "type": "AwaitExpression", + }, + "loc": SourceLocation { + "end": Position { + "column": 47, + "index": 529, + "line": 16, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 3, + "index": 485, + "line": 16, + }, + }, + "start": 485, + "type": "ExpressionStatement", + }, + ], + "directives": [], + "end": 533, + "loc": SourceLocation { + "end": Position { + "column": 3, + "index": 533, + "line": 17, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 44, + "index": 480, + "line": 15, + }, + }, + "start": 480, + "type": "BlockStatement", + }, + "end": 533, + "left": Node { + "declarations": [ + Node { + "end": 453, + "id": Node { + "end": 453, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 453, + "line": 15, + }, + "filename": undefined, + "identifierName": "task", + "start": Position { + "column": 13, + "index": 449, + "line": 15, + }, + }, + "name": "task", + "optional": false, + "start": 449, + "type": "Identifier", + "typeAnnotation": null, + }, + "init": null, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 453, + "line": 15, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 13, + "index": 449, + "line": 15, + }, + }, + "start": 449, + "type": "VariableDeclarator", + }, + ], + "end": 453, + "kind": "const", + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 453, + "line": 15, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 7, + "index": 443, + "line": 15, + }, + }, + "start": 443, + "type": "VariableDeclaration", + }, + "loc": SourceLocation { + "end": Position { + "column": 3, + "index": 533, + "line": 17, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 438, + "line": 15, + }, + }, + "right": Node { + "all": false, + "argument": Node { + "arguments": [], + "callee": Node { + "computed": false, + "end": 476, + "loc": SourceLocation { + "end": Position { + "column": 40, + "index": 476, + "line": 15, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 463, + "line": 15, + }, + }, + "object": Node { + "end": 471, + "loc": SourceLocation { + "end": Position { + "column": 35, + "index": 471, + "line": 15, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 27, + "index": 463, + "line": 15, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 463, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 476, + "loc": SourceLocation { + "end": Position { + "column": 40, + "index": 476, + "line": 15, + }, + "filename": undefined, + "identifierName": "find", + "start": Position { + "column": 36, + "index": 472, + "line": 15, + }, + }, + "name": "find", + "optional": false, + "start": 472, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 463, + "type": "MemberExpression", + }, + "end": 478, + "loc": SourceLocation { + "end": Position { + "column": 42, + "index": 478, + "line": 15, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 463, + "line": 15, + }, + }, + "optional": false, + "start": 463, + "type": "CallExpression", + "typeArguments": null, + }, + "end": 478, + "loc": SourceLocation { + "end": Position { + "column": 42, + "index": 478, + "line": 15, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 21, + "index": 457, + "line": 15, + }, + }, + "start": 457, + "type": "AwaitExpression", + }, + "start": 438, + "type": "ForOfStatement", + }, + ], + "directives": [], + "type": "BlockStatement", + }, + "test": { + "computed": false, + "object": { + "computed": false, + "object": { + "meta": { + "name": "import", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "property": { + "name": "meta", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MetaProperty", + }, + "optional": false, + "property": { + "name": "env", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MemberExpression", + }, + "optional": false, + "property": { + "name": "SSR", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MemberExpression", + }, + "type": "IfStatement", + }, + ], + "directives": [], + "end": 536, + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 536, + "line": 18, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 50, + "index": 352, + "line": 11, + }, + }, + "start": 352, + "type": "BlockStatement", + }, + "computed": false, + "decorators": [ + Node { + "end": 301, + "expression": Node { + "arguments": [ + Node { + "end": 300, + "loc": SourceLocation { + "end": Position { + "column": 48, + "index": 300, + "line": 10, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 16, + "index": 268, + "line": 10, + }, + }, + "properties": [ + Node { + "accessibility": null, + "computed": false, + "end": 298, + "key": Node { + "end": 277, + "loc": SourceLocation { + "end": Position { + "column": 25, + "index": 277, + "line": 10, + }, + "filename": undefined, + "identifierName": "allowed", + "start": Position { + "column": 18, + "index": 270, + "line": 10, + }, + }, + "name": "allowed", + "optional": false, + "start": 270, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 298, + "line": 10, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 18, + "index": 270, + "line": 10, + }, + }, + "method": false, + "shorthand": false, + "start": 270, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "end": 298, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 298, + "line": 10, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 279, + "line": 10, + }, + }, + "object": Node { + "end": 284, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 284, + "line": 10, + }, + "filename": undefined, + "identifierName": "Allow", + "start": Position { + "column": 27, + "index": 279, + "line": 10, + }, + }, + "name": "Allow", + "optional": false, + "start": 279, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 298, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 298, + "line": 10, + }, + "filename": undefined, + "identifierName": "authenticated", + "start": Position { + "column": 33, + "index": 285, + "line": 10, + }, + }, + "name": "authenticated", + "optional": false, + "start": 285, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 279, + "type": "MemberExpression", + }, + }, + ], + "start": 268, + "type": "ObjectExpression", + }, + ], + "callee": Node { + "end": 267, + "loc": SourceLocation { + "end": Position { + "column": 15, + "index": 267, + "line": 10, + }, + "filename": undefined, + "identifierName": "BackendMethod", + "start": Position { + "column": 2, + "index": 254, + "line": 10, + }, + }, + "name": "BackendMethod", + "optional": false, + "start": 254, + "type": "Identifier", + "typeAnnotation": null, + }, + "end": 301, + "loc": SourceLocation { + "end": Position { + "column": 49, + "index": 301, + "line": 10, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 254, + "line": 10, + }, + }, + "optional": false, + "start": 254, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 49, + "index": 301, + "line": 10, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 1, + "index": 253, + "line": 10, + }, + }, + "start": 253, + "type": "Decorator", + }, + ], + "defaults": [], + "definite": false, + "end": 536, + "expression": false, + "generator": false, + "id": null, + "key": Node { + "end": 331, + "loc": SourceLocation { + "end": Position { + "column": 29, + "index": 331, + "line": 11, + }, + "filename": undefined, + "identifierName": "setAllCompleted", + "start": Position { + "column": 14, + "index": 316, + "line": 11, + }, + }, + "name": "setAllCompleted", + "optional": false, + "start": 316, + "type": "Identifier", + "typeAnnotation": null, + }, + "kind": "method", + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 536, + "line": 18, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 1, + "index": 253, + "line": 10, + }, + }, + "optional": false, + "override": false, + "params": [ + Node { + "end": 350, + "loc": SourceLocation { + "end": Position { + "column": 48, + "index": 350, + "line": 11, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 30, + "index": 332, + "line": 11, + }, + }, + "name": "completed", + "optional": false, + "start": 332, + "type": "Identifier", + "typeAnnotation": Node { + "end": 350, + "loc": SourceLocation { + "end": Position { + "column": 48, + "index": 350, + "line": 11, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 39, + "index": 341, + "line": 11, + }, + }, + "start": 341, + "type": "TSTypeAnnotation", + "typeAnnotation": Node { + "end": 350, + "loc": SourceLocation { + "end": Position { + "column": 48, + "index": 350, + "line": 11, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 41, + "index": 343, + "line": 11, + }, + }, + "start": 343, + "type": "TSBooleanKeyword", + }, + }, + }, + ], + "predicate": null, + "readonly": false, + "rest": null, + "returnType": null, + "start": 253, + "static": true, + "type": "ClassMethod", + "typeParameters": null, + }, + Node { + "abstract": false, + "access": null, + "accessibility": null, + "async": true, + "body": Node { + "body": [ + { + "alternate": null, + "consequent": { + "body": [ + Node { + "declarations": [ + Node { + "end": 711, + "id": Node { + "end": 691, + "loc": SourceLocation { + "end": Position { + "column": 16, + "index": 691, + "line": 24, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 8, + "index": 683, + "line": 24, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 683, + "type": "Identifier", + "typeAnnotation": null, + }, + "init": Node { + "arguments": [ + Node { + "end": 710, + "loc": SourceLocation { + "end": Position { + "column": 35, + "index": 710, + "line": 24, + }, + "filename": undefined, + "identifierName": "Task", + "start": Position { + "column": 31, + "index": 706, + "line": 24, + }, + }, + "name": "Task", + "optional": false, + "start": 706, + "type": "Identifier", + "typeAnnotation": null, + }, + ], + "callee": Node { + "computed": false, + "end": 705, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 705, + "line": 24, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 694, + "line": 24, + }, + }, + "object": Node { + "end": 700, + "loc": SourceLocation { + "end": Position { + "column": 25, + "index": 700, + "line": 24, + }, + "filename": undefined, + "identifierName": "remult", + "start": Position { + "column": 19, + "index": 694, + "line": 24, + }, + }, + "name": "remult", + "optional": false, + "start": 694, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 705, + "loc": SourceLocation { + "end": Position { + "column": 30, + "index": 705, + "line": 24, + }, + "filename": undefined, + "identifierName": "repo", + "start": Position { + "column": 26, + "index": 701, + "line": 24, + }, + }, + "name": "repo", + "optional": false, + "start": 701, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 694, + "type": "MemberExpression", + }, + "end": 711, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 711, + "line": 24, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 19, + "index": 694, + "line": 24, + }, + }, + "optional": false, + "start": 694, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 711, + "line": 24, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 8, + "index": 683, + "line": 24, + }, + }, + "start": 683, + "type": "VariableDeclarator", + }, + ], + "end": 712, + "kind": "const", + "leadingComments": [ + { + "end": 673, + "loc": SourceLocation { + "end": Position { + "column": 45, + "index": 673, + "line": 22, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 630, + "line": 22, + }, + }, + "start": 630, + "type": "CommentLine", + "value": " console.log("AUTH_SECRET", AUTH_SECRET);", + }, + ], + "loc": SourceLocation { + "end": Position { + "column": 37, + "index": 712, + "line": 24, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 677, + "line": 24, + }, + }, + "start": 677, + "type": "VariableDeclaration", + }, + Node { + "await": false, + "body": Node { + "body": [ + Node { + "end": 806, + "expression": Node { + "all": false, + "argument": Node { + "arguments": [ + Node { + "end": 804, + "loc": SourceLocation { + "end": Position { + "column": 45, + "index": 804, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 23, + "index": 782, + "line": 26, + }, + }, + "properties": [ + Node { + "argument": Node { + "end": 791, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 791, + "line": 26, + }, + "filename": undefined, + "identifierName": "task", + "start": Position { + "column": 28, + "index": 787, + "line": 26, + }, + }, + "name": "task", + "optional": false, + "start": 787, + "type": "Identifier", + "typeAnnotation": null, + }, + "end": 791, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 791, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 25, + "index": 784, + "line": 26, + }, + }, + "start": 784, + "type": "SpreadElement", + }, + Node { + "accessibility": null, + "computed": false, + "end": 802, + "extra": { + "shorthand": true, + }, + "key": Node { + "end": 802, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 802, + "line": 26, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 34, + "index": 793, + "line": 26, + }, + }, + "name": "completed", + "optional": false, + "start": 793, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 802, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 34, + "index": 793, + "line": 26, + }, + }, + "method": false, + "shorthand": true, + "start": 793, + "type": "ObjectProperty", + "value": Node { + "end": 802, + "extra": undefined, + "loc": SourceLocation { + "end": Position { + "column": 43, + "index": 802, + "line": 26, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 34, + "index": 793, + "line": 26, + }, + }, + "name": "completed", + "optional": false, + "range": undefined, + "start": 793, + "type": "Identifier", + "typeAnnotation": null, + }, + }, + ], + "start": 782, + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "end": 781, + "loc": SourceLocation { + "end": Position { + "column": 22, + "index": 781, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 768, + "line": 26, + }, + }, + "object": Node { + "end": 776, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 776, + "line": 26, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 9, + "index": 768, + "line": 26, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 768, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 781, + "loc": SourceLocation { + "end": Position { + "column": 22, + "index": 781, + "line": 26, + }, + "filename": undefined, + "identifierName": "save", + "start": Position { + "column": 18, + "index": 777, + "line": 26, + }, + }, + "name": "save", + "optional": false, + "start": 777, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 768, + "type": "MemberExpression", + }, + "end": 805, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 805, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 9, + "index": 768, + "line": 26, + }, + }, + "optional": false, + "start": 768, + "type": "CallExpression", + "typeArguments": null, + }, + "end": 805, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 805, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 3, + "index": 762, + "line": 26, + }, + }, + "start": 762, + "type": "AwaitExpression", + }, + "loc": SourceLocation { + "end": Position { + "column": 47, + "index": 806, + "line": 26, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 3, + "index": 762, + "line": 26, + }, + }, + "start": 762, + "type": "ExpressionStatement", + }, + ], + "directives": [], + "end": 810, + "loc": SourceLocation { + "end": Position { + "column": 3, + "index": 810, + "line": 27, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 44, + "index": 757, + "line": 25, + }, + }, + "start": 757, + "type": "BlockStatement", + }, + "end": 810, + "left": Node { + "declarations": [ + Node { + "end": 730, + "id": Node { + "end": 730, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 730, + "line": 25, + }, + "filename": undefined, + "identifierName": "task", + "start": Position { + "column": 13, + "index": 726, + "line": 25, + }, + }, + "name": "task", + "optional": false, + "start": 726, + "type": "Identifier", + "typeAnnotation": null, + }, + "init": null, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 730, + "line": 25, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 13, + "index": 726, + "line": 25, + }, + }, + "start": 726, + "type": "VariableDeclarator", + }, + ], + "end": 730, + "kind": "const", + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 730, + "line": 25, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 7, + "index": 720, + "line": 25, + }, + }, + "start": 720, + "type": "VariableDeclaration", + }, + "loc": SourceLocation { + "end": Position { + "column": 3, + "index": 810, + "line": 27, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 715, + "line": 25, + }, + }, + "right": Node { + "all": false, + "argument": Node { + "arguments": [], + "callee": Node { + "computed": false, + "end": 753, + "loc": SourceLocation { + "end": Position { + "column": 40, + "index": 753, + "line": 25, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 740, + "line": 25, + }, + }, + "object": Node { + "end": 748, + "loc": SourceLocation { + "end": Position { + "column": 35, + "index": 748, + "line": 25, + }, + "filename": undefined, + "identifierName": "taskRepo", + "start": Position { + "column": 27, + "index": 740, + "line": 25, + }, + }, + "name": "taskRepo", + "optional": false, + "start": 740, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 753, + "loc": SourceLocation { + "end": Position { + "column": 40, + "index": 753, + "line": 25, + }, + "filename": undefined, + "identifierName": "find", + "start": Position { + "column": 36, + "index": 749, + "line": 25, + }, + }, + "name": "find", + "optional": false, + "start": 749, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 740, + "type": "MemberExpression", + }, + "end": 755, + "loc": SourceLocation { + "end": Position { + "column": 42, + "index": 755, + "line": 25, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 740, + "line": 25, + }, + }, + "optional": false, + "start": 740, + "type": "CallExpression", + "typeArguments": null, + }, + "end": 755, + "loc": SourceLocation { + "end": Position { + "column": 42, + "index": 755, + "line": 25, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 21, + "index": 734, + "line": 25, + }, + }, + "start": 734, + "type": "AwaitExpression", + }, + "start": 715, + "type": "ForOfStatement", + }, + ], + "directives": [], + "type": "BlockStatement", + }, + "test": { + "computed": false, + "object": { + "computed": false, + "object": { + "meta": { + "name": "import", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "property": { + "name": "meta", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MetaProperty", + }, + "optional": false, + "property": { + "name": "env", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MemberExpression", + }, + "optional": false, + "property": { + "name": "SSR", + "optional": false, + "type": "Identifier", + "typeAnnotation": null, + }, + "type": "MemberExpression", + }, + "type": "IfStatement", + }, + ], + "directives": [], + "end": 813, + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 813, + "line": 28, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 38, + "index": 626, + "line": 21, + }, + }, + "start": 626, + "type": "BlockStatement", + }, + "computed": false, + "decorators": [ + Node { + "end": 587, + "expression": Node { + "arguments": [ + Node { + "end": 586, + "loc": SourceLocation { + "end": Position { + "column": 48, + "index": 586, + "line": 20, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 16, + "index": 554, + "line": 20, + }, + }, + "properties": [ + Node { + "accessibility": null, + "computed": false, + "end": 584, + "key": Node { + "end": 563, + "loc": SourceLocation { + "end": Position { + "column": 25, + "index": 563, + "line": 20, + }, + "filename": undefined, + "identifierName": "allowed", + "start": Position { + "column": 18, + "index": 556, + "line": 20, + }, + }, + "name": "allowed", + "optional": false, + "start": 556, + "type": "Identifier", + "typeAnnotation": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 584, + "line": 20, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 18, + "index": 556, + "line": 20, + }, + }, + "method": false, + "shorthand": false, + "start": 556, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "end": 584, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 584, + "line": 20, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 565, + "line": 20, + }, + }, + "object": Node { + "end": 570, + "loc": SourceLocation { + "end": Position { + "column": 32, + "index": 570, + "line": 20, + }, + "filename": undefined, + "identifierName": "Allow", + "start": Position { + "column": 27, + "index": 565, + "line": 20, + }, + }, + "name": "Allow", + "optional": false, + "start": 565, + "type": "Identifier", + "typeAnnotation": null, + }, + "optional": false, + "property": Node { + "end": 584, + "loc": SourceLocation { + "end": Position { + "column": 46, + "index": 584, + "line": 20, + }, + "filename": undefined, + "identifierName": "authenticated", + "start": Position { + "column": 33, + "index": 571, + "line": 20, + }, + }, + "name": "authenticated", + "optional": false, + "start": 571, + "type": "Identifier", + "typeAnnotation": null, + }, + "start": 565, + "type": "MemberExpression", + }, + }, + ], + "start": 554, + "type": "ObjectExpression", + }, + ], + "callee": Node { + "end": 553, + "loc": SourceLocation { + "end": Position { + "column": 15, + "index": 553, + "line": 20, + }, + "filename": undefined, + "identifierName": "BackendMethod", + "start": Position { + "column": 2, + "index": 540, + "line": 20, + }, + }, + "name": "BackendMethod", + "optional": false, + "start": 540, + "type": "Identifier", + "typeAnnotation": null, + }, + "end": 587, + "loc": SourceLocation { + "end": Position { + "column": 49, + "index": 587, + "line": 20, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 2, + "index": 540, + "line": 20, + }, + }, + "optional": false, + "start": 540, + "type": "CallExpression", + "typeArguments": null, + }, + "loc": SourceLocation { + "end": Position { + "column": 49, + "index": 587, + "line": 20, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 1, + "index": 539, + "line": 20, + }, + }, + "start": 539, + "type": "Decorator", + }, + ], + "defaults": [], + "definite": false, + "end": 813, + "expression": false, + "generator": false, + "id": null, + "key": Node { + "end": 605, + "loc": SourceLocation { + "end": Position { + "column": 17, + "index": 605, + "line": 21, + }, + "filename": undefined, + "identifierName": "Yop", + "start": Position { + "column": 14, + "index": 602, + "line": 21, + }, + }, + "name": "Yop", + "optional": false, + "start": 602, + "type": "Identifier", + "typeAnnotation": null, + }, + "kind": "method", + "loc": SourceLocation { + "end": Position { + "column": 2, + "index": 813, + "line": 28, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 1, + "index": 539, + "line": 20, + }, + }, + "optional": false, + "override": false, + "params": [ + Node { + "end": 624, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 624, + "line": 21, + }, + "filename": undefined, + "identifierName": "completed", + "start": Position { + "column": 18, + "index": 606, + "line": 21, + }, + }, + "name": "completed", + "optional": false, + "start": 606, + "type": "Identifier", + "typeAnnotation": Node { + "end": 624, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 624, + "line": 21, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 27, + "index": 615, + "line": 21, + }, + }, + "start": 615, + "type": "TSTypeAnnotation", + "typeAnnotation": Node { + "end": 624, + "loc": SourceLocation { + "end": Position { + "column": 36, + "index": 624, + "line": 21, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 29, + "index": 617, + "line": 21, + }, + }, + "start": 617, + "type": "TSBooleanKeyword", + }, + }, + }, + ], + "predicate": null, + "readonly": false, + "rest": null, + "returnType": null, + "start": 539, + "static": true, + "type": "ClassMethod", + "typeParameters": null, + }, + ], + "end": 815, + "loc": SourceLocation { + "end": Position { + "column": 1, + "index": 815, + "line": 29, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 29, + "index": 167, + "line": 5, + }, + }, + "start": 167, + "type": "ClassBody", + }, + "end": 815, + "id": Node { + "end": 166, + "loc": SourceLocation { + "end": Position { + "column": 28, + "index": 166, + "line": 5, + }, + "filename": undefined, + "identifierName": "TasksController", + "start": Position { + "column": 13, + "index": 151, + "line": 5, + }, + }, + "name": "TasksController", + "optional": false, + "start": 151, + "type": "Identifier", + "typeAnnotation": null, + }, + "implements": [], + "loc": SourceLocation { + "end": Position { + "column": 1, + "index": 815, + "line": 29, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 7, + "index": 145, + "line": 5, + }, + }, + "start": 145, + "superClass": null, + "superTypeParameters": null, + "type": "ClassDeclaration", + "typeParameters": null, + }, + "end": 815, + "exportKind": "value", + "loc": SourceLocation { + "end": Position { + "column": 1, + "index": 815, + "line": 29, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 138, + "line": 5, + }, + }, + "source": null, + "specifiers": [], + "start": 138, + "type": "ExportNamedDeclaration", + }, + ], + "directives": [], + "end": 817, + "extra": { + "topLevelAwait": false, + }, + "interpreter": null, + "loc": SourceLocation { + "end": Position { + "column": 1, + "index": 817, + "line": 30, + }, + "filename": undefined, + "identifierName": undefined, + "start": Position { + "column": 0, + "index": 0, + "line": 1, + }, + }, + "sourceType": "module", + "start": 0, + "type": "Program", + }, + "start": 0, + "type": "File", + }, "info": [ "Wrapped with if(import.meta.env.SSR): ["TasksController","BackendMethod","setAllCompleted"]", "Wrapped with if(import.meta.env.SSR): ["TasksController","BackendMethod","Yop"]", @@ -182,7 +3341,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, remult } from "remult"; import { Task } from "./task"; @@ -223,7 +3382,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, remult } from "remult"; import { Task } from "./task"; @@ -282,7 +3441,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { TOP_SECRET, TOP_SECRET_NOT_USED } from "$env/static/private"; import { stry0 } from "@kitql/helper"; @@ -341,7 +3500,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, Entity, Fields, Validators } from "remult"; @@ -395,7 +3554,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, Entity, Fields, Validators } from "remult"; @@ -447,7 +3606,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, Entity, Fields, Validators } from "remult"; @@ -501,7 +3660,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { Allow, BackendMethod, Entity, Fields, Validators } from "remult"; @@ -552,7 +3711,7 @@ export class TasksController { const transformed = await transformStrip(code, [{ decorator: 'BackendMethod' }]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "import { AUTH_SECRET } from "$env/static/private"; import { BackendMethod, type Allowed, remult } from "remult"; @@ -605,12 +3764,12 @@ export class User { } ` - const code1 = await nullifyImports(code, ['$env/static/private']) - const transformed = await transformStrip(code1.code, [ + const ast_1 = await nullifyImports(code, ['$env/static/private']) + const transformed = await transformStrip(ast_1.code_ast, [ { decorator: 'BackendMethod' }, { decorator: 'Entity', args_1: [{ fn: 'backendPrefilter' }] }, ]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "let AUTH_SECRET = null; let AUTH_SECRET_NOT_USED = null; @@ -677,8 +3836,8 @@ export class User { } ` - const code1 = await nullifyImports(code, ['$env/static/private']) - const transformed = await transformStrip(code1.code, [ + const ast_1 = await nullifyImports(code, ['$env/static/private']) + const transformed = await transformStrip(ast_1.code_ast, [ { decorator: 'BackendMethod' }, { decorator: 'Entity', @@ -690,7 +3849,7 @@ export class User { ], }, ]) - expect(transformed).toMatchInlineSnapshot(` + expect(toInfoCode(transformed)).toMatchInlineSnapshot(` { "code": "let AUTH_SECRET = null; let AUTH_SECRET_NOT_USED = null; diff --git a/packages/vite-plugin-stripper/src/lib/transformStrip.ts b/packages/vite-plugin-stripper/src/lib/transformStrip.ts index 0965eb11..dcd75169 100644 --- a/packages/vite-plugin-stripper/src/lib/transformStrip.ts +++ b/packages/vite-plugin-stripper/src/lib/transformStrip.ts @@ -1,4 +1,4 @@ -import { parseTs, prettyPrint, visit } from '@kitql/internals' +import { parse, visit, type ParseResult } from '@kitql/internals' // Define the type for the decorator config export type StripConfig = { @@ -6,9 +6,12 @@ export type StripConfig = { args_1?: { fn: string; excludeEntityKeys?: string[] }[] // Array of objects with function name and optional entity keys to exclude } -export const transformStrip = async (code: string, decorators_config: StripConfig[]) => { +export const transformStrip = async ( + code_ast: string | ParseResult, + decorators_config: StripConfig[], +) => { try { - const program = parseTs(code) + const ast = parse(code_ast) let currentClassName = '' // Variable to hold the current class name const decorators_wrapped: { decorator: string; functionName: string; className: string }[] = [] @@ -16,7 +19,7 @@ export const transformStrip = async (code: string, decorators_config: StripConfi const entityNameMap = new Map() // Map class names to their entity names // First pass: identify classes with special decorators and filters - visit(program, { + visit(ast, { visitClassDeclaration(path: any) { // @ts-ignore const className = path.node.id.name @@ -117,7 +120,7 @@ export const transformStrip = async (code: string, decorators_config: StripConfi }) // Second pass: wrap functions with decorators in if(import.meta.env.SSR) condition - visit(program, { + visit(ast, { visitClassDeclaration(path: any) { // @ts-ignore currentClassName = path.node.id.name @@ -235,16 +238,15 @@ export const transformStrip = async (code: string, decorators_config: StripConfi }, }) - const res = prettyPrint(program, {}) const info = decorators_wrapped.map( (decorator) => `Wrapped with if(import.meta.env.SSR): ${JSON.stringify(Object.values(decorator))}`, ) - return { ...res, info } + return { code_ast: ast, info } } catch (error) { // if anything happens, just return the original code console.error('Error in transformDecorator:', error) - return { code, info: [] } + return { code_ast, info: [] } } } diff --git a/packages/vite-plugin-stripper/src/lib/transformWarningThrow.ts b/packages/vite-plugin-stripper/src/lib/transformWarningThrow.ts index e483a4f9..e5a63982 100644 --- a/packages/vite-plugin-stripper/src/lib/transformWarningThrow.ts +++ b/packages/vite-plugin-stripper/src/lib/transformWarningThrow.ts @@ -1,4 +1,4 @@ -import { parseTs, visit } from '@kitql/internals' +import { parse, visit } from '@kitql/internals' export type WarningThrow = { relativePathFile: string @@ -13,7 +13,7 @@ export const transformWarningThrow = async ( log_on_throw_is_not_a_new_class: boolean, ) => { try { - const codeParsed = parseTs(code) + const codeParsed = parse(code) const list: WarningThrow[] = [] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df99a4ec..4db79dd8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,10 +5,6 @@ settings: excludeLinksFromLockfile: false catalogs: - default: - '@vitest/ui': - specifier: 3.0.4 - version: 3.0.4 docs: '@astrojs/starlight': specifier: 0.32.2 @@ -153,6 +149,9 @@ catalogs: '@vitest/coverage-v8': specifier: 3.0.4 version: 3.0.4 + '@vitest/ui': + specifier: 3.0.4 + version: 3.0.4 jsdom: specifier: 26.0.0 version: 26.0.0 @@ -161,8 +160,11 @@ catalogs: version: 3.0.4 tooling: '@babel/parser': - specifier: 7.26.9 - version: 7.26.9 + specifier: 7.26.10 + version: 7.26.10 + '@babel/types': + specifier: 7.26.10 + version: 7.26.10 commander: specifier: 13.1.0 version: 13.1.0 @@ -408,7 +410,10 @@ importers: dependencies: '@babel/parser': specifier: catalog:tooling - version: 7.26.9 + version: 7.26.10 + '@babel/types': + specifier: catalog:tooling + version: 7.26.10 '@kitql/helpers': specifier: workspace:* version: link:../helpers/dist @@ -578,7 +583,7 @@ importers: specifier: catalog:sveltekit version: 5.0.1(svelte@5.23.0)(vite@6.2.1(@types/node@22.13.9)(jiti@1.21.7)(lightningcss@1.28.2)(sass@1.85.1)(terser@5.37.0)(tsx@4.19.3)(yaml@2.7.0)) '@vitest/ui': - specifier: 'catalog:' + specifier: catalog:testing version: 3.0.4(vitest@3.0.4) publint: specifier: catalog:lib-author-helper @@ -734,6 +739,11 @@ packages: resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/parser@7.26.10': + resolution: {integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/parser@7.26.9': resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} engines: {node: '>=6.0.0'} @@ -751,12 +761,8 @@ packages: resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.0': - resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.26.9': - resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + '@babel/types@7.26.10': + resolution: {integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': @@ -4953,7 +4959,7 @@ snapshots: '@babel/generator@7.26.2': dependencies: '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 + '@babel/types': 7.26.10 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.0.2 @@ -4962,9 +4968,13 @@ snapshots: '@babel/helper-validator-identifier@7.25.9': {} + '@babel/parser@7.26.10': + dependencies: + '@babel/types': 7.26.10 + '@babel/parser@7.26.9': dependencies: - '@babel/types': 7.26.9 + '@babel/types': 7.26.10 '@babel/runtime@7.24.4': dependencies: @@ -4974,7 +4984,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 + '@babel/types': 7.26.10 '@babel/traverse@7.25.9': dependencies: @@ -4982,18 +4992,13 @@ snapshots: '@babel/generator': 7.26.2 '@babel/parser': 7.26.9 '@babel/template': 7.25.9 - '@babel/types': 7.26.9 + '@babel/types': 7.26.10 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.26.0': - dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - - '@babel/types@7.26.9': + '@babel/types@7.26.10': dependencies: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 @@ -5352,7 +5357,7 @@ snapshots: '@babel/generator': 7.26.2 '@babel/parser': 7.26.9 '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/types': 7.26.10 prettier: 3.5.3 semver: 7.7.1 optionalDependencies: @@ -6182,7 +6187,7 @@ snapshots: '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.26.9 + '@babel/parser': 7.26.10 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 @@ -6197,7 +6202,7 @@ snapshots: '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.26.9 + '@babel/parser': 7.26.10 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 @@ -7842,7 +7847,7 @@ snapshots: magicast@0.3.5: dependencies: '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 + '@babel/types': 7.26.10 source-map-js: 1.2.1 make-dir@4.0.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cbf2d8a6..2b241842 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,11 +12,12 @@ catalogs: tooling: 'typescript': '5.8.2' 'esbuild': '0.25.0' - '@babel/parser': 7.26.9 + '@babel/parser': 7.26.10 + '@babel/types': 7.26.10 'rimraf': '6.0.1' 'commander': '13.1.0' 'ora': '8.2.0' - 'recast': '^0.23.4' # to remove ? + 'recast': '^0.23.4' vite: 'vite': '6.2.1' @@ -24,6 +25,7 @@ catalogs: testing: # unit 'vitest': '3.0.4' + '@vitest/ui': 3.0.4 '@vitest/coverage-v8': '3.0.4' '@testing-library/jest-dom': '6.6.3' '@testing-library/svelte': '5.2.4' @@ -88,5 +90,3 @@ catalogs: astro-icon: 1.1.5 sharp: 0.33.5 prettier-plugin-astro: 0.14.1 -catalog: - '@vitest/ui': 3.0.4