babel-plugin-saykit 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,30 +2,9 @@ let node_path = require("node:path");
2
2
  let node_fs = require("node:fs");
3
3
  let _saykit_config_features_catalogue = require("@saykit/config/features/catalogue");
4
4
  //#region src/catalogue.ts
5
- /** Normalise an absolute path into the form bucket globs are written against. */
6
5
  const toId = (path) => (0, node_path.relative)(process.cwd(), path).replaceAll("\\", "/").split("?")[0];
7
- /**
8
- * The glob a bucket's catalogues match, e.g. `src/locales/*.po` — the `output`
9
- * template with its placeholders filled in. Bundlers that select files by glob
10
- * rather than by predicate need this to target exactly the catalogues, and
11
- * nothing else sharing their extension.
12
- */
13
6
  const catalogueGlob = (bucket) => String(bucket.output).replace("{locale}", "*").replace("{extension}", bucket.formatter.extension.slice(1)).replaceAll("\\", "/").replace(/^\.\//, "");
14
- /** Whether `path` is one of the config's catalogue outputs. */
15
7
  const isCatalogue = (config, path) => config.buckets.some((bucket) => bucket.output.match(toId(path)));
16
- /**
17
- * Assemble the catalogue at `path` into a `{ id: string }` record, merging in
18
- * the fallback chain (configured fallbacks + the source locale) so an
19
- * untranslated key resolves to a fallback string rather than going missing.
20
- *
21
- * Returns `undefined` when the path is not a catalogue, and otherwise reports
22
- * the files that fed the record alongside it — a bundler that can track them
23
- * gets invalidation for free when a fallback locale is edited.
24
- *
25
- * Reads are synchronous so every caller can share one implementation: Babel's
26
- * visitor cannot await, and the handful of files in a fallback chain are not
27
- * worth an async path in a bundler that is blocked on the result anyway.
28
- */
29
8
  function loadCatalogue(config, path) {
30
9
  const id = toId(path);
31
10
  const bucket = config.buckets.find((b) => b.output.match(id));
package/dist/index.cjs CHANGED
@@ -1,9 +1,8 @@
1
- const require_catalogue = require("./catalogue-B3HA3aVz.cjs");
1
+ const require_catalogue = require("./catalogue-CrZhNHS_.cjs");
2
2
  let node_path = require("node:path");
3
- let _babel_core = require("@babel/core");
4
3
  let _saykit_config_features_loader = require("@saykit/config/features/loader");
5
4
  //#region src/index.ts
6
- var src_default = (_, { catalogues = "inline" } = {}) => {
5
+ var src_default = ({ types: t }, { catalogues = "inline" } = {}) => {
7
6
  const config = (0, _saykit_config_features_loader.resolveConfig)();
8
7
  return {
9
8
  name: "saykit",
@@ -16,7 +15,7 @@ var src_default = (_, { catalogues = "inline" } = {}) => {
16
15
  if (!catalogue) return;
17
16
  const [specifier, ...rest] = path.node.specifiers;
18
17
  if (specifier?.type !== "ImportDefaultSpecifier" || rest.length > 0) throw path.buildCodeFrameError("SayKit inline imports require a single default import");
19
- path.replaceWith(_babel_core.types.variableDeclaration("const", [_babel_core.types.variableDeclarator(_babel_core.types.identifier(specifier.local.name), _babel_core.types.objectExpression(Object.entries(catalogue.record).map(([key, value]) => _babel_core.types.objectProperty(_babel_core.types.stringLiteral(key), _babel_core.types.stringLiteral(value)))))]));
18
+ path.replaceWith(t.variableDeclaration("const", [t.variableDeclarator(t.identifier(specifier.local.name), t.objectExpression(Object.entries(catalogue.record).map(([key, value]) => t.objectProperty(t.stringLiteral(key), t.stringLiteral(value)))))]));
20
19
  } },
21
20
  parserOverride(code, opts, parse) {
22
21
  const id_ = opts.sourceFileName;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PluginObj, parse } from "@babel/core";
1
+ import { ConfigAPI, PluginObj, parse, types } from "@babel/core";
2
2
  //#region src/index.d.ts
3
3
  declare module '@babel/core' {
4
4
  interface PluginObj {
@@ -21,6 +21,8 @@ interface Options {
21
21
  */
22
22
  catalogues?: 'inline' | 'module';
23
23
  }
24
- declare const _default: (_: unknown, { catalogues }?: Options) => PluginObj;
24
+ declare const _default: ({ types: t }: ConfigAPI & {
25
+ types: typeof types;
26
+ }, { catalogues }?: Options) => PluginObj;
25
27
  //#endregion
26
28
  export { Options, _default as default };
@@ -3,13 +3,6 @@ let node_path = require("node:path");
3
3
  let _saykit_config_features_loader = require("@saykit/config/features/loader");
4
4
  let node_module = require("node:module");
5
5
  //#region src/metro/index.ts
6
- /**
7
- * Resolve Metro's own transformer from the project rather than from this
8
- * package, since it is the project that depends on Metro.
9
- *
10
- * The base is the config's `projectRoot` — `process.cwd()` is wrong whenever
11
- * Metro is started from elsewhere, which in a monorepo is the normal case.
12
- */
13
6
  const transformerPath = (0, node_path.join)(__dirname, "transformer.cjs");
14
7
  function resolveUpstream(specifier, projectRoot) {
15
8
  if ((0, node_path.isAbsolute)(specifier)) return specifier;
@@ -19,21 +12,6 @@ function resolveUpstream(specifier, projectRoot) {
19
12
  return require.resolve(specifier);
20
13
  }
21
14
  }
22
- /**
23
- * Wrap a Metro config so SayKit catalogues load as real modules.
24
- *
25
- * ```js
26
- * const { withSayKit } = require('babel-plugin-saykit/metro');
27
- * module.exports = withSayKit(getDefaultConfig(__dirname));
28
- * ```
29
- *
30
- * Metro's transform cache is keyed on each file's own bytes, so a catalogue has
31
- * to stay a module of its own to be invalidated at all — see
32
- * `./transformer.ts`.
33
- *
34
- * Apply this outermost. Anything wrapped around it that also sets
35
- * `transformerPath` replaces this one, and catalogues stop being assembled.
36
- */
37
15
  function withSayKit(metroConfig) {
38
16
  if (metroConfig.transformerPath === transformerPath) return metroConfig;
39
17
  const extensions = (0, _saykit_config_features_loader.resolveConfig)().buckets.map((bucket) => bucket.formatter.extension.slice(1)).filter((extension) => extension !== "json");
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_catalogue = require("../catalogue-B3HA3aVz.cjs");
2
+ const require_catalogue = require("../catalogue-CrZhNHS_.cjs");
3
3
  let node_path = require("node:path");
4
4
  let _saykit_config_features_loader = require("@saykit/config/features/loader");
5
5
  let node_fs = require("node:fs");
@@ -7,21 +7,7 @@ let node_crypto = require("node:crypto");
7
7
  //#region src/metro/transformer.ts
8
8
  const config = (0, _saykit_config_features_loader.resolveConfig)();
9
9
  const upstream = (transformerConfig) => require(transformerConfig.saykitTransformerPath);
10
- /**
11
- * What a catalogue transforms into depends on the SayKit config — the fallback
12
- * chain it resolves, the formatter that parses it — and on the version of this
13
- * package doing the assembling. Neither is a byte of the file Metro hashes, so
14
- * without them in the cache key, editing `saykit.config.*` or upgrading leaves
15
- * every catalogue serving the record it was cached with.
16
- */
17
10
  const salt = (0, node_crypto.createHash)("sha1").update((0, node_fs.readFileSync)((0, node_path.join)(__dirname, "..", "..", "package.json"), "utf8")).update((0, node_fs.readFileSync)((0, _saykit_config_features_loader.resolveConfigFile)(), "utf8")).digest("hex");
18
- /**
19
- * Metro reads `.json` straight through `transformJSON` and never runs Babel over
20
- * it, so a Babel plugin cannot reach a catalogue at all. Wrapping the transform
21
- * worker is the one place that can: it substitutes the assembled record for the
22
- * catalogue's own source, leaving the file a real module whose sha1 — and
23
- * therefore Metro's transform cache entry — moves whenever it is edited.
24
- */
25
11
  function transform(transformerConfig, projectRoot, filename, data, options) {
26
12
  const worker = upstream(transformerConfig);
27
13
  const catalogue = require_catalogue.loadCatalogue(config, filename);
@@ -1,24 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_catalogue = require("../catalogue-B3HA3aVz.cjs");
2
+ const require_catalogue = require("../catalogue-CrZhNHS_.cjs");
3
3
  let _saykit_config_features_loader = require("@saykit/config/features/loader");
4
4
  //#region src/next/index.ts
5
5
  const loader = "babel-plugin-saykit/next/loader";
6
- /**
7
- * Wrap a Next config so SayKit catalogues load as real modules.
8
- *
9
- * ```js
10
- * import { withSayKit } from 'babel-plugin-saykit/next';
11
- * export default withSayKit({});
12
- * ```
13
- *
14
- * Pair it with `catalogues: 'module'` on the Babel plugin — the plugin has to
15
- * leave the import alone for the loader to ever be asked for the module.
16
- *
17
- * Rules are derived from the SayKit config, so both bundlers get one per bucket
18
- * targeting exactly that bucket's `output` — nothing else sharing the extension
19
- * goes through the loader, which matters most for a `.json` bucket, where the
20
- * alternative would be routing every JSON import in the app through it.
21
- */
22
6
  function withSayKit(nextConfig = {}) {
23
7
  const config = (0, _saykit_config_features_loader.resolveConfig)();
24
8
  const rules = Object.fromEntries(config.buckets.map((bucket) => [`**/${require_catalogue.catalogueGlob(bucket)}`, {
@@ -1,20 +1,6 @@
1
- const require_catalogue = require("../catalogue-B3HA3aVz.cjs");
1
+ const require_catalogue = require("../catalogue-CrZhNHS_.cjs");
2
2
  //#region src/next/loader.ts
3
3
  const config = (0, require("@saykit/config/features/loader").resolveConfig)();
4
- /**
5
- * Replaces a catalogue file with its assembled record.
6
- *
7
- * This is a *loader* rather than a plugin because Turbopack runs loaders and
8
- * not webpack plugins, and it is published only so `withSayKit` can name it in
9
- * the rules it generates. A plain webpack, Vite or Rollup build should reach for
10
- * `unplugin-saykit` instead, which does the same job through each bundler's own
11
- * plugin API.
12
- *
13
- * The catalogue stays a real module, which is the whole point: the importer
14
- * keeps a dependency edge to it, so editing a catalogue invalidates exactly the
15
- * modules that read it. Inlining the record into the importer instead leaves the
16
- * importer's own bytes unchanged, and no bundler can invalidate on that.
17
- */
18
4
  function saykitLoader(source) {
19
5
  const catalogue = require_catalogue.loadCatalogue(config, this.resourcePath);
20
6
  if (!catalogue) return source;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babel-plugin-saykit",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Babel plugin for SayKit",
5
5
  "keywords": [
6
6
  "i18n",
@@ -48,12 +48,15 @@
48
48
  "provenance": true
49
49
  },
50
50
  "dependencies": {
51
- "@babel/core": "^7.29.7",
52
- "@saykit/config": "^0.8.0"
51
+ "@saykit/config": "^0.9.0"
53
52
  },
54
53
  "devDependencies": {
54
+ "@babel/core": "^7.29.7",
55
55
  "@types/babel__core": "^7.20.5"
56
56
  },
57
+ "peerDependencies": {
58
+ "@babel/core": "^7.0.0 || ^8.0.0"
59
+ },
57
60
  "scripts": {
58
61
  "check": "tsc --noEmit",
59
62
  "build": "tsdown"