Skip to content

Commit

Permalink
fix: working on ast instead of string for script tag (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
sahinvardar authored Oct 29, 2024
1 parent 1bfabac commit 2f65016
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 47 deletions.
21 changes: 12 additions & 9 deletions src/extract-i18n-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import _ from 'lodash';
import fs from 'node:fs/promises';
import path from 'node:path';
import { walk } from 'estree-walker';
import { extractKeyPathFromFile, stripScriptTag } from './string-utils.js';
import { extractKeyPathFromFile } from './string-utils.js';
import { scanDir } from './utils.js';
import { preprocess, PreprocessorGroup, parse } from 'svelte/compiler';
import printAst from '@vardario/svelte-ast-printer';

function extractI18nKeys(root: any, callIdentifier: string): string[] {
const result: string[] = [];
Expand Down Expand Up @@ -49,15 +50,17 @@ export async function processSvelteFile(
const preprocessExtract = (): PreprocessorGroup => {
return {
async markup({ content, filename }) {
const { code } = stripScriptTag(rawCode);
const ast = parse(code, { modern: true });
const ast = parse(content, { modern: true });
keys.push(...extractI18nKeys(ast.fragment, callIdentifier));
return { code: content };
},
async script({ content, filename }) {
const ast = acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'module' }) as Node;
keys.push(...extractI18nKeys(ast, callIdentifier));
return { code: content };
if (ast.instance) {
keys.push(...extractI18nKeys(ast.instance.content, callIdentifier));
}

if (ast.module) {
keys.push(...extractI18nKeys(ast.module.content, callIdentifier));
}

return { code: printAst(ast) };
}
};
};
Expand Down
13 changes: 5 additions & 8 deletions src/i18n-preprocessor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import printHtml, { PrinterIdentOptions } from '@vardario/svelte-ast-printer';
import { PrinterIdentOptions } from '@vardario/svelte-ast-printer';
import { parse as scriptParse } from 'acorn';
import { CallExpression, Node } from 'estree';
import { walk } from 'estree-walker';
import { addPrefixToI18nArgument, extractKeyPathFromFile, stripScriptTag } from './string-utils.js';
import { extractKeyPathFromFile } from './string-utils.js';
import { AST, type PreprocessorGroup, parse as svelteParse } from 'svelte/compiler';
import printAst from '@vardario/svelte-ast-printer';

export function create18nCallLabelAttribute(callIdentifier: string, i18nKey: string) {
const expression = scriptParse(`${callIdentifier}("${i18nKey}")`, { ecmaVersion: 'latest' });
Expand Down Expand Up @@ -114,16 +115,12 @@ export const i18nProcessor = (options?: I18nProcessorOptions): PreprocessorGroup
return {
async markup({ content, filename }) {
return preprocess(content, filename, async () => {
const { code, scriptTags } = stripScriptTag(content);
const root = svelteParse(code, { modern: true });
const root = svelteParse(content, { modern: true });
const keyPath = extractKeyPathFromFile(filename!);

adjustI18nKeys(root, keyPath, callIdentifier);

const processedScriptTags = scriptTags.map(tag => addPrefixToI18nArgument(tag, keyPath));
const transformedCode = printHtml(root, options?.indent);
const result = `${processedScriptTags.join('\n')}${processedScriptTags.length ? '\n' : ''}${transformedCode}`;
return { code: result };
return { code: printAst(root, options?.indent) };
});
}
};
Expand Down
11 changes: 0 additions & 11 deletions src/string-utils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import path from 'node:path';

export function stripScriptTag(code: string) {
const scriptTagRegEx = /(<script[\s\S]*?[\s\S\]*?>[\s\S]*?<\/script>)/gi;
const scriptTags: string[] = [];

for (const match of code.matchAll(scriptTagRegEx)) {
scriptTags.push(match[0]);
}

return { code: code.replace(scriptTagRegEx, ''), scriptTags };
}

export function extractKeyPathFromFile(filename: string) {
filename = filename.split('.').slice(0, -1).join('.');
const regEx = /(components|routes)/;
Expand Down
20 changes: 1 addition & 19 deletions src/tests/string-utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'node:path';
import { describe, expect, test } from 'vitest';
import { addPrefixToI18nArgument, extractKeyPathFromFile, stripScriptTag } from '../string-utils.js';
import { addPrefixToI18nArgument, extractKeyPathFromFile } from '../string-utils.js';
import { __dirname } from '../utils.js';

describe('string-utils', () => {
Expand All @@ -17,24 +17,6 @@ describe('string-utils', () => {
);
});

test('stripScriptTag', () => {
const result0 = stripScriptTag('<script lang="ts">let a;</script><main/>');
const result1 = stripScriptTag('<script>let a;</script><main/>');
const result2 = stripScriptTag('<script lang="ts">let a;</script><script context="module">let a;</script><main/>');

expect(result0.code).toBe('<main/>');
expect(result0.scriptTags).toStrictEqual(['<script lang="ts">let a;</script>']);

expect(result1.code).toBe('<main/>');
expect(result1.scriptTags).toStrictEqual(['<script>let a;</script>']);

expect(result2.code).toBe('<main/>');
expect(result2.scriptTags).toStrictEqual([
'<script lang="ts">let a;</script>',
'<script context="module">let a;</script>'
]);
});

test('addPrefixToI18nArgument', () => {
expect(addPrefixToI18nArgument("const a = $i18n('key')", 'prefix')).toBe("const a = $i18n('prefix.key')");
expect(addPrefixToI18nArgument("const a = $i18n('key', { count: 1 })", 'prefix')).toBe(
Expand Down

0 comments on commit 2f65016

Please sign in to comment.