Skip to content

Commit

Permalink
Merge pull request #3379 from opral/new-paraglide-beta-releases
Browse files Browse the repository at this point in the history
new paraglide beta release
  • Loading branch information
samuelstroschein authored Jan 30, 2025
2 parents 5ee2c79 + eee6e27 commit e3186b1
Show file tree
Hide file tree
Showing 22 changed files with 329 additions and 159 deletions.
2 changes: 2 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"@inlang/cli",
"@inlang/fink",
"@inlang/paraglide-js",
"@inlang/paraglide-next",
"@inlang/paraglide-astro",
"@inlang/paraglide-sveltekit",
"@inlang/paraglide-js-example-cli",
"@inlang/paraglide-js-example-vite",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "paraglide-js compile --project ./project.inlang && astro check && astro build",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props {
image?: string;
}
const { title, description, image = "/blog-placeholder-1.jpg" } = Astro.props;
const { title, description } = Astro.props;
const pathWithoutLocale = deLocalizePath(Astro.url.pathname);
---
Expand Down
6 changes: 4 additions & 2 deletions inlang/packages/paraglide/paraglide-astro/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@inlang/paraglide-astro",
"version": "1.0.0-beta.3",
"version": "1.0.0-beta.4",
"author": "inlang <[email protected]> (https://inlang.com/)",
"description": "A fully type-safe i18n library specifically designed for partial hydration patterns like Astro's islands.",
"homepage": "https://inlang.com/m/iljlwzfs/paraglide-astro-i18n",
Expand All @@ -22,8 +22,10 @@
"format": "prettier ./src --write",
"clean": "rm -rf ./dist ./node_modules"
},
"dependencies": {
"@inlang/paraglide-js": "workspace:*"
},
"peerDependencies": {
"@inlang/paraglide-js": "^2",
"astro": "^4 || ^5"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ import { compile, type CompilerOptions } from "../compiler/compile.js";
import fs from "node:fs";
import { resolve } from "node:path";
import { nodeNormalizePath } from "../utilities/node-normalize-path.js";
import { Logger } from "../cli/index.js";

const PLUGIN_NAME = "unplugin-paraglide-js";

const logger = new Logger();

let compilationResult: Awaited<ReturnType<typeof compile>> | undefined;

export const unpluginFactory: UnpluginFactory<CompilerOptions> = (args) => ({
name: PLUGIN_NAME,
enforce: "pre",
async buildStart() {
await compile({
logger.info("Compiling inlang project...");
compilationResult = await compile({
fs: wrappedFs,
...args,
});
logger.success("Compilation complete");

for (const path of Array.from(readFiles)) {
this.addWatchFile(path);
Expand All @@ -23,10 +30,15 @@ export const unpluginFactory: UnpluginFactory<CompilerOptions> = (args) => ({
const shouldCompile = readFiles.has(path) && !path.includes("cache");
if (shouldCompile) {
readFiles.clear();
await compile({
fs: wrappedFs,
...args,
});
logger.info("Re-compiling inlang project...");
compilationResult = await compile(
{
fs: wrappedFs,
...args,
},
compilationResult?.outputHashes
);
logger.success("Compilation complete");
}
},
webpack(compiler) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ export const runCompiler: CliStep<
project: ctx.project,
});

await writeOutput(absoluteOutdir, output, ctx.fs);
await writeOutput({ directory: absoluteOutdir, output, fs: ctx.fs });
return { ...ctx };
};
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,17 @@ const mockBundle: BundleNested = {
},
],
};

test("throws if a JS keyword is used as an identifier", async () => {
expect(() =>
compileBundle({
fallbackMap: {},
registry: {},
bundle: {
id: "then",
declarations: [],
messages: [],
},
})
).toThrow();
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import { jsIdentifier } from "../services/codegen/identifier.js";
import { isValidJSIdentifier } from "../services/valid-js-identifier/index.js";
import { escapeForDoubleQuoteString } from "../services/codegen/escape.js";
import type { Compiled } from "./types.js";
import {
jsDocBundleFunctionTypes,
jsDocMessageFunctionTypes,
} from "./jsdoc-types.js";
import { jsDocBundleFunctionTypes } from "./jsdoc-types.js";
import { KEYWORDS } from "../services/valid-js-identifier/reserved-words.js";

export type CompiledBundleWithMessages = {
/** The compilation result for the bundle index */
Expand All @@ -29,6 +27,16 @@ export const compileBundle = (args: {
}): CompiledBundleWithMessages => {
const compiledMessages: Record<string, Compiled<Message>> = {};

if (KEYWORDS.includes(args.bundle.id) || args.bundle.id === "then") {
throw new Error(
[
`You are using a reserved JS keyword as id "${args.bundle.id}".`,
"Rename the message bundle id to something else.",
"See https://github.com/opral/inlang-paraglide-js/issues/331",
].join("\n")
);
}

for (const message of args.bundle.messages) {
if (compiledMessages[message.locale]) {
throw new Error(`Duplicate locale: ${message.locale}`);
Expand All @@ -40,12 +48,6 @@ export const compileBundle = (args: {
message.variants,
args.registry
);
// add types to the compiled message function
const inputs = args.bundle.declarations.filter(
(decl) => decl.type === "input-variable"
);

compiledMessage.code = `${jsDocMessageFunctionTypes({ inputs })}\n${compiledMessage.code}`;

// set the pattern for the language tag
compiledMessages[message.locale] = compiledMessage;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { it, expect } from "vitest";
import { test, expect } from "vitest";
import { compileMessage } from "./compile-message.js";
import type { Declaration, Message, Variant } from "@inlang/sdk";
import { DEFAULT_REGISTRY } from "./registry.js";

it("compiles a message with a single variant", async () => {
test("compiles a message with a single variant", async () => {
const declarations: Declaration[] = [];
const message: Message = {
locale: "en",
Expand Down Expand Up @@ -34,7 +34,7 @@ it("compiles a message with a single variant", async () => {
expect(some_message()).toBe("Hello");
});

it("compiles a message with variants", async () => {
test("compiles a message with variants", async () => {
const declarations: Declaration[] = [
{ type: "input-variable", name: "fistInput" },
{ type: "input-variable", name: "secondInput" },
Expand Down Expand Up @@ -99,3 +99,35 @@ it("compiles a message with variants", async () => {
expect(some_message({ fistInput: 3, secondInput: 4 })).toBe("Catch all");
expect(some_message({ fistInput: 1, secondInput: 5 })).toBe("Catch all");
});

test("only emits input arguments when inputs exist", async () => {
const declarations: Declaration[] = [];
const message: Message = {
locale: "en",
bundleId: "some_message",
id: "message-id",
selectors: [],
};
const variants: Variant[] = [
{
id: "1",
messageId: "message-id",
matches: [],
pattern: [{ type: "text", value: "Hello" }],
},
];

const compiled = compileMessage(
declarations,
message,
variants,
DEFAULT_REGISTRY
);

expect(compiled.code, "single variant").toBe(
[
"/** @type {(inputs: {}) => string} */",
"export const some_message = () => `Hello`;",
].join("\n")
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import type { Registry } from "./registry.js";
import { compilePattern } from "./compile-pattern.js";
import type { Compiled } from "./types.js";
import { doubleQuote } from "../services/codegen/quotes.js";
import { inputsType } from "./jsdoc-types.js";

/**
* Returns the compiled message as a string
*
* @example
* @param message The message to compile
* @returns (inputs) => string
*/
export const compileMessage = (
declarations: Declaration[],
Expand All @@ -21,6 +19,7 @@ export const compileMessage = (
if (variants.length == 0) {
throw new Error("Message must have at least one variant");
}

const hasMultipleVariants = variants.length > 1;
return hasMultipleVariants
? compileMessageWithMultipleVariants(
Expand All @@ -29,10 +28,11 @@ export const compileMessage = (
variants,
registry
)
: compileMessageWithOneVariant(message, variants, registry);
: compileMessageWithOneVariant(declarations, message, variants, registry);
};

function compileMessageWithOneVariant(
declarations: Declaration[],
message: Message,
variants: Variant[],
registry: Registry
Expand All @@ -41,12 +41,15 @@ function compileMessageWithOneVariant(
if (!variant || variants.length !== 1) {
throw new Error("Message must have exactly one variant");
}
const inputs = declarations.filter((decl) => decl.type === "input-variable");
const hasInputs = inputs.length > 0;
const compiledPattern = compilePattern(
message.locale,
variant.pattern,
registry
);
const code = `export const ${message.bundleId} = (i) => ${compiledPattern.code}`;
const code = `/** @type {(inputs: ${inputsType(inputs)}) => string} */
export const ${message.bundleId} = (${hasInputs ? "i" : ""}) => ${compiledPattern.code};`;
return { code, node: message };
}

Expand All @@ -56,8 +59,12 @@ function compileMessageWithMultipleVariants(
variants: Variant[],
registry: Registry
): Compiled<Message> {
if (variants.length <= 1)
if (variants.length <= 1) {
throw new Error("Message must have more than one variant");
}

const inputs = declarations.filter((decl) => decl.type === "input-variable");
const hasInputs = inputs.length > 0;

// TODO make sure that matchers use keys instead of indexes
const compiledVariants = [];
Expand Down Expand Up @@ -101,9 +108,10 @@ function compileMessageWithMultipleVariants(
);
}

const code = `export const ${message.bundleId} = (i) => {
const code = `/** @type {(inputs: ${inputsType(inputs)}) => string} */
export const ${message.bundleId} = (${hasInputs ? "i" : ""}) => {
${compiledVariants.join("\n\t")}
}`;
};`;

return { code, node: message };
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expect, test, describe, vi, beforeEach } from "vitest";
import { createProject as typescriptProject, ts } from "@ts-morph/bootstrap";
import {
createProject as typescriptProject,
ts,
type ProjectOptions,
} from "@ts-morph/bootstrap";
import {
type BundleNested,
Declaration,
Expand Down Expand Up @@ -381,22 +385,32 @@ describe.each([
});
});

// whatever the strictest users use, this is the ultimate nothing gets stricter than this
// (to avoid developers opening issues "i get a ts warning in my code")
const superStrictRuleOutAnyErrorTsSettings: ProjectOptions["compilerOptions"] =
{
outDir: "dist",
declaration: true,
allowJs: true,
checkJs: true,
noImplicitAny: true,
noUnusedLocals: true,
noUnusedParameters: true,
noImplicitReturns: true,
noImplicitThis: true,
noUncheckedIndexedAccess: true,
noPropertyAccessFromIndexSignature: true,
module: ts.ModuleKind.Node16,
strict: true,
};

// remove with v3 of paraglide js
test("./runtime.js types", async () => {
const project = await typescriptProject({
useInMemoryFileSystem: true,
compilerOptions: {
outDir: "dist",
declaration: true,
allowJs: true,
checkJs: true,
module: ts.ModuleKind.Node16,
strict: true,
},
compilerOptions: superStrictRuleOutAnyErrorTsSettings,
});

console.log(output["runtime.js"]);

for (const [fileName, code] of Object.entries(output)) {
if (fileName.endsWith(".js") || fileName.endsWith(".ts")) {
project.createSourceFile(fileName, code);
Expand Down Expand Up @@ -424,12 +438,18 @@ describe.each([
// isLocale should narrow the type of it's argument
const thing = 5;
let a: "de" | "en" | "en-US";
if(runtime.isLocale(thing)) {
const a : "de" | "en" | "en-US" = thing
a = thing
} else {
// @ts-expect-error - thing is not a language tag
const a : "de" | "en" | "en-US" = thing
a = thing
}
// to make ts not complain about unused variables
console.log(a)
`
);

Expand All @@ -444,14 +464,7 @@ describe.each([
test("./messages.js types", async () => {
const project = await typescriptProject({
useInMemoryFileSystem: true,
compilerOptions: {
outDir: "dist",
declaration: true,
allowJs: true,
checkJs: true,
module: ts.ModuleKind.Node16,
strict: true,
},
compilerOptions: superStrictRuleOutAnyErrorTsSettings,
});

for (const [fileName, code] of Object.entries(output)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ export const compileProject = async (args: {
}

for (const [filename, content] of Object.entries(output)) {
if (filename.endsWith(".js") || filename.endsWith(".ts")) {
output[filename] = `// @ts-nocheck\n${output[filename]}`;
}
if (optionsWithDefaults.includeEslintDisableComment) {
if (filename.endsWith(".js")) {
output[filename] = `// eslint-disable\n${content}`;
Expand Down
Loading

0 comments on commit e3186b1

Please sign in to comment.