prettier-plugin-intlayer 0.0.0-stage → 9.7.1

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.
Files changed (36) hide show
  1. package/README.md +46 -2
  2. package/dist/cjs/@intlayer/core/dist/esm/interpreter/getEnumeration.cjs +42 -0
  3. package/dist/cjs/@intlayer/core/dist/esm/interpreter/getEnumeration.cjs.map +1 -0
  4. package/dist/cjs/collapseTranslations.cjs +73 -0
  5. package/dist/cjs/collapseTranslations.cjs.map +1 -0
  6. package/dist/cjs/index.cjs +84 -0
  7. package/dist/cjs/index.cjs.map +1 -0
  8. package/dist/cjs/keyOrderings.cjs +135 -0
  9. package/dist/cjs/keyOrderings.cjs.map +1 -0
  10. package/dist/cjs/sortContentKeys.cjs +86 -0
  11. package/dist/cjs/sortContentKeys.cjs.map +1 -0
  12. package/dist/cjs/sortContentNodes.cjs +131 -0
  13. package/dist/cjs/sortContentNodes.cjs.map +1 -0
  14. package/dist/esm/@intlayer/core/dist/esm/interpreter/getEnumeration.mjs +42 -0
  15. package/dist/esm/@intlayer/core/dist/esm/interpreter/getEnumeration.mjs.map +1 -0
  16. package/dist/esm/collapseTranslations.mjs +72 -0
  17. package/dist/esm/collapseTranslations.mjs.map +1 -0
  18. package/dist/esm/index.mjs +70 -0
  19. package/dist/esm/index.mjs.map +1 -0
  20. package/dist/esm/keyOrderings.mjs +128 -0
  21. package/dist/esm/keyOrderings.mjs.map +1 -0
  22. package/dist/esm/sortContentKeys.mjs +84 -0
  23. package/dist/esm/sortContentKeys.mjs.map +1 -0
  24. package/dist/esm/sortContentNodes.mjs +123 -0
  25. package/dist/esm/sortContentNodes.mjs.map +1 -0
  26. package/dist/types/collapseTranslations.d.ts +8 -0
  27. package/dist/types/collapseTranslations.d.ts.map +1 -0
  28. package/dist/types/index.d.ts +12 -0
  29. package/dist/types/index.d.ts.map +1 -0
  30. package/dist/types/keyOrderings.d.ts +36 -0
  31. package/dist/types/keyOrderings.d.ts.map +1 -0
  32. package/dist/types/sortContentKeys.d.ts +8 -0
  33. package/dist/types/sortContentKeys.d.ts.map +1 -0
  34. package/dist/types/sortContentNodes.d.ts +46 -0
  35. package/dist/types/sortContentNodes.d.ts.map +1 -0
  36. package/package.json +94 -4
@@ -0,0 +1,123 @@
1
+ import { createLocaleOrdering, orderEnumerationConditions, orderPluralCategories, orderSelectCases } from "./keyOrderings.mjs";
2
+
3
+ // src/sortContentNodes.ts
4
+ /** Helper function name → content node type it declares. */
5
+ const NODE_TYPE_BY_FUNCTION_NAME = {
6
+ t: "translation",
7
+ plural: "plural",
8
+ enu: "enumeration",
9
+ select: "select"
10
+ };
11
+ const SORTED_NODE_TYPES = new Set(Object.values(NODE_TYPE_BY_FUNCTION_NAME));
12
+ /** Fields never walked: positions, comments and back-references. */
13
+ const IGNORED_FIELDS = /* @__PURE__ */ new Set([
14
+ "loc",
15
+ "range",
16
+ "start",
17
+ "end",
18
+ "extra",
19
+ "parent",
20
+ "comments",
21
+ "leadingComments",
22
+ "trailingComments",
23
+ "innerComments",
24
+ "tokens"
25
+ ]);
26
+ const isAstNode = (value) => typeof value === "object" && value !== null && typeof value.type === "string";
27
+ const isObjectExpression = (node) => isAstNode(node) && node.type === "ObjectExpression";
28
+ const getStringLiteralValue = (node) => isAstNode(node) && (node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string" ? node.value : void 0;
29
+ const getNumericLiteralKey = (node) => (node.type === "NumericLiteral" || node.type === "Literal") && typeof node.value === "number" ? String(node.value) : void 0;
30
+ /**
31
+ * Static name of an object property key (`en`, `'en-GB'`, `2`), or
32
+ * `undefined` when the key is computed.
33
+ */
34
+ const getStaticKeyName = (property) => {
35
+ if (property.computed) return void 0;
36
+ const key = property.key;
37
+ if (!isAstNode(key)) return void 0;
38
+ if (key.type === "Identifier") return key.name;
39
+ return getStringLiteralValue(key) ?? getNumericLiteralKey(key);
40
+ };
41
+ const isPlainProperty = (property) => isAstNode(property) && (property.type === "Property" || property.type === "ObjectProperty") && property.kind !== "get" && property.kind !== "set" && !property.method;
42
+ /**
43
+ * Reorders the properties of a content map in place. Objects holding a
44
+ * spread, a computed key or a method are left untouched: their order may be
45
+ * meaningful.
46
+ */
47
+ const sortObjectProperties = (objectNode, orderKeys) => {
48
+ const properties = objectNode.properties;
49
+ if (!Array.isArray(properties) || properties.length < 2) return;
50
+ if (!properties.every(isPlainProperty)) return;
51
+ const propertyByName = /* @__PURE__ */ new Map();
52
+ for (const property of properties) {
53
+ const name = getStaticKeyName(property);
54
+ if (name === void 0 || propertyByName.has(name)) return;
55
+ propertyByName.set(name, property);
56
+ }
57
+ const orderedNames = orderKeys([...propertyByName.keys()]);
58
+ if (!orderedNames) return;
59
+ objectNode.properties = orderedNames.map((name) => propertyByName.get(name));
60
+ };
61
+ /** `t({...})`, `plural({...})`, `enu({...})`, `select({...})`, `x.t({...})`. */
62
+ const getHelperCallContent = (node) => {
63
+ if (node.type !== "CallExpression") return void 0;
64
+ const callee = node.callee;
65
+ if (!isAstNode(callee)) return void 0;
66
+ const calleeName = callee.type === "Identifier" ? callee.name : callee.type === "MemberExpression" && !callee.computed && isAstNode(callee.property) ? callee.property.name : void 0;
67
+ const nodeType = typeof calleeName === "string" ? NODE_TYPE_BY_FUNCTION_NAME[calleeName] : void 0;
68
+ const [firstArgument] = node.arguments;
69
+ if (!nodeType || !isObjectExpression(firstArgument)) return void 0;
70
+ return {
71
+ nodeType,
72
+ content: firstArgument
73
+ };
74
+ };
75
+ /**
76
+ * `{ nodeType: 'plural', plural: {...} }`, the serialized form used by
77
+ * `.content.json` files and the CMS.
78
+ */
79
+ const getSerializedNodeContent = (node) => {
80
+ if (!isObjectExpression(node)) return void 0;
81
+ const properties = node.properties.filter(isPlainProperty);
82
+ const findPropertyValue = (name) => properties.find((property) => getStaticKeyName(property) === name)?.value;
83
+ const nodeType = getStringLiteralValue(findPropertyValue("nodeType"));
84
+ if (!nodeType || !SORTED_NODE_TYPES.has(nodeType)) return void 0;
85
+ const content = findPropertyValue(nodeType);
86
+ return isObjectExpression(content) ? {
87
+ nodeType,
88
+ content
89
+ } : void 0;
90
+ };
91
+ /**
92
+ * Walks a Prettier AST and sorts, in place, the keys of every Intlayer
93
+ * translation (locales), plural (CLDR categories), enumeration (thresholds)
94
+ * and select (cases).
95
+ */
96
+ const sortContentNodesInAst = (rootNode, pinnedLocales) => {
97
+ const orderingByNodeType = {
98
+ translation: createLocaleOrdering(pinnedLocales),
99
+ plural: orderPluralCategories,
100
+ enumeration: orderEnumerationConditions,
101
+ select: orderSelectCases
102
+ };
103
+ const visitedNodes = /* @__PURE__ */ new WeakSet();
104
+ const pendingValues = [rootNode];
105
+ while (pendingValues.length > 0) {
106
+ const value = pendingValues.pop();
107
+ if (typeof value !== "object" || value === null) continue;
108
+ if (visitedNodes.has(value)) continue;
109
+ visitedNodes.add(value);
110
+ if (Array.isArray(value)) {
111
+ pendingValues.push(...value);
112
+ continue;
113
+ }
114
+ if (isAstNode(value)) {
115
+ const contentNode = getHelperCallContent(value) ?? getSerializedNodeContent(value);
116
+ if (contentNode) sortObjectProperties(contentNode.content, orderingByNodeType[contentNode.nodeType]);
117
+ }
118
+ for (const [field, child] of Object.entries(value)) if (!IGNORED_FIELDS.has(field)) pendingValues.push(child);
119
+ }
120
+ };
121
+
122
+ export { getHelperCallContent, getSerializedNodeContent, getStaticKeyName, isAstNode, isObjectExpression, isPlainProperty, sortContentNodesInAst, sortObjectProperties };
123
+ //# sourceMappingURL=sortContentNodes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortContentNodes.mjs","names":[],"sources":["../../src/sortContentNodes.ts"],"sourcesContent":["import {\n createLocaleOrdering,\n type KeyOrdering,\n orderEnumerationConditions,\n orderPluralCategories,\n orderSelectCases,\n} from './keyOrderings';\n\n/**\n * Minimal shape shared by the Babel, TypeScript-ESTree, Acorn and JSON ASTs\n * Prettier produces. Only the fields this module reads are typed.\n */\nexport type AstNode = {\n type: string;\n [field: string]: unknown;\n};\n\n/** Content node types whose keys get sorted. */\ntype SortedNodeType = 'translation' | 'plural' | 'enumeration' | 'select';\n\n/** Helper function name → content node type it declares. */\nconst NODE_TYPE_BY_FUNCTION_NAME: Record<string, SortedNodeType> = {\n t: 'translation',\n plural: 'plural',\n enu: 'enumeration',\n select: 'select',\n};\n\nconst SORTED_NODE_TYPES = new Set<string>(\n Object.values(NODE_TYPE_BY_FUNCTION_NAME)\n);\n\n/** Fields never walked: positions, comments and back-references. */\nconst IGNORED_FIELDS = new Set([\n 'loc',\n 'range',\n 'start',\n 'end',\n 'extra',\n 'parent',\n 'comments',\n 'leadingComments',\n 'trailingComments',\n 'innerComments',\n 'tokens',\n]);\n\nexport const isAstNode = (value: unknown): value is AstNode =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as AstNode).type === 'string';\n\nexport const isObjectExpression = (node: unknown): node is AstNode =>\n isAstNode(node) && node.type === 'ObjectExpression';\n\nconst getStringLiteralValue = (node: unknown): string | undefined =>\n isAstNode(node) &&\n (node.type === 'StringLiteral' || node.type === 'Literal') &&\n typeof node.value === 'string'\n ? node.value\n : undefined;\n\nconst getNumericLiteralKey = (node: AstNode): string | undefined =>\n (node.type === 'NumericLiteral' || node.type === 'Literal') &&\n typeof node.value === 'number'\n ? String(node.value)\n : undefined;\n\n/**\n * Static name of an object property key (`en`, `'en-GB'`, `2`), or\n * `undefined` when the key is computed.\n */\nexport const getStaticKeyName = (property: AstNode): string | undefined => {\n if (property.computed) return undefined;\n\n const key = property.key;\n\n if (!isAstNode(key)) return undefined;\n if (key.type === 'Identifier') return key.name as string;\n\n return getStringLiteralValue(key) ?? getNumericLiteralKey(key);\n};\n\nexport const isPlainProperty = (property: unknown): property is AstNode =>\n isAstNode(property) &&\n (property.type === 'Property' || property.type === 'ObjectProperty') &&\n property.kind !== 'get' &&\n property.kind !== 'set' &&\n !property.method;\n\n/**\n * Reorders the properties of a content map in place. Objects holding a\n * spread, a computed key or a method are left untouched: their order may be\n * meaningful.\n */\nexport const sortObjectProperties = (\n objectNode: AstNode,\n orderKeys: KeyOrdering\n): void => {\n const properties = objectNode.properties;\n\n if (!Array.isArray(properties) || properties.length < 2) return;\n if (!properties.every(isPlainProperty)) return;\n\n const propertyByName = new Map<string, AstNode>();\n\n for (const property of properties) {\n const name = getStaticKeyName(property);\n\n if (name === undefined || propertyByName.has(name)) return;\n\n propertyByName.set(name, property);\n }\n\n const orderedNames = orderKeys([...propertyByName.keys()]);\n\n if (!orderedNames) return;\n\n objectNode.properties = orderedNames.map(\n (name) => propertyByName.get(name) as AstNode\n );\n};\n\n/** `t({...})`, `plural({...})`, `enu({...})`, `select({...})`, `x.t({...})`. */\nexport const getHelperCallContent = (\n node: AstNode\n): { nodeType: SortedNodeType; content: AstNode } | undefined => {\n if (node.type !== 'CallExpression') return undefined;\n\n const callee = node.callee;\n\n if (!isAstNode(callee)) return undefined;\n\n const calleeName =\n callee.type === 'Identifier'\n ? callee.name\n : callee.type === 'MemberExpression' &&\n !callee.computed &&\n isAstNode(callee.property)\n ? callee.property.name\n : undefined;\n const nodeType =\n typeof calleeName === 'string'\n ? NODE_TYPE_BY_FUNCTION_NAME[calleeName]\n : undefined;\n const [firstArgument] = node.arguments as unknown[];\n\n if (!nodeType || !isObjectExpression(firstArgument)) return undefined;\n\n return { nodeType, content: firstArgument };\n};\n\n/**\n * `{ nodeType: 'plural', plural: {...} }`, the serialized form used by\n * `.content.json` files and the CMS.\n */\nexport const getSerializedNodeContent = (\n node: AstNode\n): { nodeType: SortedNodeType; content: AstNode } | undefined => {\n if (!isObjectExpression(node)) return undefined;\n\n const properties = (node.properties as unknown[]).filter(isPlainProperty);\n const findPropertyValue = (name: string): unknown =>\n properties.find((property) => getStaticKeyName(property) === name)?.value;\n const nodeType = getStringLiteralValue(findPropertyValue('nodeType'));\n\n if (!nodeType || !SORTED_NODE_TYPES.has(nodeType)) return undefined;\n\n const content = findPropertyValue(nodeType);\n\n return isObjectExpression(content)\n ? { nodeType: nodeType as SortedNodeType, content }\n : undefined;\n};\n\n/**\n * Walks a Prettier AST and sorts, in place, the keys of every Intlayer\n * translation (locales), plural (CLDR categories), enumeration (thresholds)\n * and select (cases).\n */\nexport const sortContentNodesInAst = (\n rootNode: unknown,\n pinnedLocales: readonly string[]\n): void => {\n const orderingByNodeType: Record<SortedNodeType, KeyOrdering> = {\n translation: createLocaleOrdering(pinnedLocales),\n plural: orderPluralCategories,\n enumeration: orderEnumerationConditions,\n select: orderSelectCases,\n };\n const visitedNodes = new WeakSet<object>();\n const pendingValues: unknown[] = [rootNode];\n\n while (pendingValues.length > 0) {\n const value = pendingValues.pop();\n\n if (typeof value !== 'object' || value === null) continue;\n if (visitedNodes.has(value)) continue;\n\n visitedNodes.add(value);\n\n if (Array.isArray(value)) {\n pendingValues.push(...value);\n continue;\n }\n\n if (isAstNode(value)) {\n const contentNode =\n getHelperCallContent(value) ?? getSerializedNodeContent(value);\n\n if (contentNode) {\n sortObjectProperties(\n contentNode.content,\n orderingByNodeType[contentNode.nodeType]\n );\n }\n }\n\n for (const [field, child] of Object.entries(value)) {\n if (!IGNORED_FIELDS.has(field)) pendingValues.push(child);\n }\n }\n};\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Replaces, in place, every translation whose locales all hold the same
3
+ * string by that string: `t({ en: 'Next.js', fr: 'Next.js' })` → `'Next.js'`.
4
+ *
5
+ * Translations holding a comment are kept, so no comment is lost.
6
+ */
7
+ export declare const collapseIdenticalTranslationsInAst: (rootNode: unknown) => void;
8
+ //# sourceMappingURL=collapseTranslations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapseTranslations.d.ts","names":[],"sources":["../../src/collapseTranslations.ts"],"mappings":";;;;;;qBAoGa,qCAAsC"}
@@ -0,0 +1,12 @@
1
+ import { collapseIdenticalTranslationsInAst } from "./collapseTranslations.js";
2
+ import { PLURAL_CATEGORY_ORDER, createLocaleComparator, orderAlphabetically, orderEnumerationConditions, orderPluralCategories, orderSelectCases } from "./keyOrderings.js";
3
+ import { isContentFile, sortContentKeysInAst } from "./sortContentKeys.js";
4
+ import { sortContentNodesInAst } from "./sortContentNodes.js";
5
+ import { Plugin, SupportOptions } from "prettier";
6
+ /** Locales kept at the top of every translation when none are configured. */
7
+ export declare const DEFAULT_PINNED_LOCALES: readonly ["en"];
8
+ export declare const parsers: Plugin['parsers'];
9
+ export declare const options: SupportOptions;
10
+ declare const plugin: Plugin;
11
+ export { PLURAL_CATEGORY_ORDER, collapseIdenticalTranslationsInAst, createLocaleComparator, plugin as default, isContentFile, orderAlphabetically, orderEnumerationConditions, orderPluralCategories, orderSelectCases, sortContentKeysInAst, sortContentNodesInAst };
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;;;qBAuBa;qBAkDA,SAAS;qBAeT,SAAS;cAyBhB,QAAQ"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Returns the given keys in their canonical order, or `undefined` when the
3
+ * keys must keep their current order.
4
+ */
5
+ export type KeyOrdering = (keys: readonly string[]) => string[] | undefined;
6
+ /** Plain alphabetical order, for the keys of a content object. */
7
+ export declare const orderAlphabetically: KeyOrdering;
8
+ /**
9
+ * Builds the comparator ordering locales: pinned locales first (in the given
10
+ * order), then every other locale alphabetically.
11
+ */
12
+ export declare const createLocaleComparator: (pinnedLocales: readonly string[]) => (localeA: string, localeB: string) => number;
13
+ /** Locale order for `t()`: pinned locales, then alphabetical. */
14
+ export declare const createLocaleOrdering: (pinnedLocales: readonly string[]) => KeyOrdering;
15
+ /** CLDR plural categories, from the smallest quantity to the fallback. */
16
+ export declare const PLURAL_CATEGORY_ORDER: readonly ["zero", "one", "two", "few", "many", "other"];
17
+ /**
18
+ * CLDR order for `plural()`. Unknown keys leave the object untouched.
19
+ */
20
+ export declare const orderPluralCategories: KeyOrdering;
21
+ /**
22
+ * Ascending threshold order for `enu()`, `fallback` last.
23
+ *
24
+ * The first matching condition wins at runtime, so the new order is applied
25
+ * only when it selects the same branch for every quantity; overlapping
26
+ * conditions whose priority depends on their position are left untouched.
27
+ */
28
+ export declare const orderEnumerationConditions: KeyOrdering;
29
+ /**
30
+ * Alphabetical order for `select()`, `fallback` last.
31
+ *
32
+ * Without a `fallback` or `other` key, the last key is the implicit fallback,
33
+ * so it stays last and only the keys before it are sorted.
34
+ */
35
+ export declare const orderSelectCases: KeyOrdering;
36
+ //# sourceMappingURL=keyOrderings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyOrderings.d.ts","names":[],"sources":["../../src/keyOrderings.ts"],"mappings":";;;;YAOY,eAAe;;qBASd,qBAAqB;;;;;qBAOrB,yBAA0B,sCAK7B,iBAAiB;;qBAWd,uBACX,qCACC;;qBAOU;;;;qBAYA,uBAAuB;;;;;;;;qBA0GvB,4BAA4B;;;;;;;qBAyC5B,kBAAkB"}
@@ -0,0 +1,8 @@
1
+ /** True when Prettier is formatting an Intlayer content declaration file. */
2
+ export declare const isContentFile: (filePath: string | undefined) => boolean;
3
+ /**
4
+ * Sorts, in place, the keys of every dictionary `content` object of the AST,
5
+ * and of their nested objects, alphabetically.
6
+ */
7
+ export declare const sortContentKeysInAst: (rootNode: unknown) => void;
8
+ //# sourceMappingURL=sortContentKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortContentKeys.d.ts","names":[],"sources":["../../src/sortContentKeys.ts"],"mappings":";qBA0Ba,gBAAiB;;;;;qBA2FjB,uBAAwB"}
@@ -0,0 +1,46 @@
1
+ import { KeyOrdering } from "./keyOrderings.js";
2
+ /**
3
+ * Minimal shape shared by the Babel, TypeScript-ESTree, Acorn and JSON ASTs
4
+ * Prettier produces. Only the fields this module reads are typed.
5
+ */
6
+ export type AstNode = {
7
+ type: string;
8
+ [field: string]: unknown;
9
+ };
10
+ /** Content node types whose keys get sorted. */
11
+ type SortedNodeType = 'translation' | 'plural' | 'enumeration' | 'select';
12
+ export declare const isAstNode: (value: unknown) => value is AstNode;
13
+ export declare const isObjectExpression: (node: unknown) => node is AstNode;
14
+ /**
15
+ * Static name of an object property key (`en`, `'en-GB'`, `2`), or
16
+ * `undefined` when the key is computed.
17
+ */
18
+ export declare const getStaticKeyName: (property: AstNode) => string | undefined;
19
+ export declare const isPlainProperty: (property: unknown) => property is AstNode;
20
+ /**
21
+ * Reorders the properties of a content map in place. Objects holding a
22
+ * spread, a computed key or a method are left untouched: their order may be
23
+ * meaningful.
24
+ */
25
+ export declare const sortObjectProperties: (objectNode: AstNode, orderKeys: KeyOrdering) => void;
26
+ /** `t({...})`, `plural({...})`, `enu({...})`, `select({...})`, `x.t({...})`. */
27
+ export declare const getHelperCallContent: (node: AstNode) => {
28
+ nodeType: SortedNodeType;
29
+ content: AstNode;
30
+ } | undefined;
31
+ /**
32
+ * `{ nodeType: 'plural', plural: {...} }`, the serialized form used by
33
+ * `.content.json` files and the CMS.
34
+ */
35
+ export declare const getSerializedNodeContent: (node: AstNode) => {
36
+ nodeType: SortedNodeType;
37
+ content: AstNode;
38
+ } | undefined;
39
+ /**
40
+ * Walks a Prettier AST and sorts, in place, the keys of every Intlayer
41
+ * translation (locales), plural (CLDR categories), enumeration (thresholds)
42
+ * and select (cases).
43
+ */
44
+ export declare const sortContentNodesInAst: (rootNode: unknown, pinnedLocales: readonly string[]) => void;
45
+ export {};
46
+ //# sourceMappingURL=sortContentNodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortContentNodes.d.ts","names":[],"sources":["../../src/sortContentNodes.ts"],"mappings":";;;;;YAYY;EACV;GACC;;;KAIE;qBA6BQ,YAAa,mBAAiB,SAAS;qBAKvC,qBAAsB,kBAAgB,QAAQ;;;;;qBAoB9C,mBAAoB,UAAU;qBAW9B,kBAAmB,sBAAoB,YAAY;;;;;;qBAYnD,uBACX,YAAY,SACZ,WAAW;;qBA2BA,uBACX,MAAM;EACH,UAAU;EAAgB,SAAS;;;;;;qBA8B3B,2BACX,MAAM;EACH,UAAU;EAAgB,SAAS;;;;;;;qBAsB3B,wBACX,mBACA"}
package/package.json CHANGED
@@ -1,6 +1,96 @@
1
1
  {
2
2
  "name": "prettier-plugin-intlayer",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "9.7.1",
4
+ "private": false,
5
+ "description": "Prettier plugin for Intlayer. Sorts t() locales alphabetically (pinned locales first), plural() categories in CLDR order and enu() conditions by threshold.",
6
+ "keywords": [
7
+ "intlayer",
8
+ "prettier",
9
+ "prettier-plugin",
10
+ "i18n",
11
+ "internationalization",
12
+ "format",
13
+ "sort"
14
+ ],
15
+ "homepage": "https://intlayer.org",
16
+ "bugs": {
17
+ "url": "https://github.com/aymericzip/intlayer/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/aymericzip/intlayer.git"
22
+ },
23
+ "license": "Apache-2.0",
24
+ "author": {
25
+ "name": "Aymeric PINEAU",
26
+ "url": "https://github.com/aymericzip"
27
+ },
28
+ "contributors": [
29
+ {
30
+ "name": "Aymeric Pineau",
31
+ "email": "ay.pineau@gmail.com",
32
+ "url": "https://github.com/aymericzip"
33
+ }
34
+ ],
35
+ "sideEffects": false,
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/types/index.d.ts",
39
+ "require": "./dist/cjs/index.cjs",
40
+ "import": "./dist/esm/index.mjs"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
44
+ "main": "dist/cjs/index.cjs",
45
+ "module": "dist/esm/index.mjs",
46
+ "types": "dist/types/index.d.ts",
47
+ "typesVersions": {
48
+ "*": {
49
+ ".": [
50
+ "./dist/types/index.d.ts"
51
+ ],
52
+ "package.json": [
53
+ "./package.json"
54
+ ]
55
+ }
56
+ },
57
+ "files": [
58
+ "./dist",
59
+ "./package.json"
60
+ ],
61
+ "scripts": {
62
+ "build": "bun --bun tsdown --config tsdown.config.ts",
63
+ "build:ci": "bun --bun tsdown --config tsdown.config.ts",
64
+ "clean": "bun --bun rimraf ./dist .turbo",
65
+ "dev": "bun --bun tsdown --config tsdown.config.ts --watch",
66
+ "format": "bun --bun biome format . --check",
67
+ "format:fix": "bun --bun biome format --write .",
68
+ "lint": "bun --bun biome lint .",
69
+ "lint:fix": "bun --bun biome lint --write .",
70
+ "publish": "bun publish || true",
71
+ "publish:canary": "bun publish --access public --tag canary || true",
72
+ "publish:ci": "bun ../../scripts/publish-package.mjs",
73
+ "publish:latest": "bun publish --access public --tag latest || true",
74
+ "test": "bun --bun vitest run",
75
+ "test:watch": "bun --bun vitest",
76
+ "typecheck": "tsc --noEmit --project tsconfig.types.json"
77
+ },
78
+ "devDependencies": {
79
+ "@intlayer/core": "9.7.1",
80
+ "@types/node": "^26",
81
+ "@utils/ts-config": "1.0.4",
82
+ "@utils/ts-config-types": "1.0.4",
83
+ "@utils/tsdown-config": "1.0.4",
84
+ "prettier": "3.9.10",
85
+ "rimraf": "6.1.3",
86
+ "tsdown": "0.23.4",
87
+ "typescript": "6.0.3",
88
+ "vitest": "5.1.0"
89
+ },
90
+ "peerDependencies": {
91
+ "prettier": ">=3.0.0"
92
+ },
93
+ "engines": {
94
+ "node": ">=18.0.0"
95
+ }
96
+ }