repopo 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.
Files changed (98) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/THIRD-PARTY-LICENSES.txt +4 -3
  3. package/esm/adapters/fluidFramework.js +8 -3
  4. package/esm/adapters/fluidFramework.js.map +1 -1
  5. package/esm/baseCommand.d.ts.map +1 -1
  6. package/esm/baseCommand.js +2 -1
  7. package/esm/baseCommand.js.map +1 -1
  8. package/esm/commands/check.d.ts.map +1 -1
  9. package/esm/commands/check.js +69 -44
  10. package/esm/commands/check.js.map +1 -1
  11. package/esm/commands/list.d.ts.map +1 -1
  12. package/esm/commands/list.js +3 -1
  13. package/esm/commands/list.js.map +1 -1
  14. package/esm/generators.d.ts +30 -2
  15. package/esm/generators.d.ts.map +1 -1
  16. package/esm/generators.js +31 -1
  17. package/esm/generators.js.map +1 -1
  18. package/esm/index.d.ts +13 -3
  19. package/esm/index.d.ts.map +1 -1
  20. package/esm/index.js +12 -2
  21. package/esm/index.js.map +1 -1
  22. package/esm/makePolicy.d.ts +31 -2
  23. package/esm/makePolicy.d.ts.map +1 -1
  24. package/esm/makePolicy.js +27 -13
  25. package/esm/makePolicy.js.map +1 -1
  26. package/esm/perf.d.ts +3 -2
  27. package/esm/perf.d.ts.map +1 -1
  28. package/esm/perf.js +2 -2
  29. package/esm/perf.js.map +1 -1
  30. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  31. package/esm/policies/HtmlFileHeaders.js +11 -7
  32. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  33. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  34. package/esm/policies/JsTsFileHeaders.js +11 -7
  35. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  36. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  37. package/esm/policies/LicenseFileExists.js +22 -18
  38. package/esm/policies/LicenseFileExists.js.map +1 -1
  39. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  40. package/esm/policies/NoJsFileExtensions.js +16 -12
  41. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  42. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  43. package/esm/policies/NoLargeBinaryFiles.js +35 -31
  44. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  45. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  46. package/esm/policies/NoPrivateWorkspaceDependencies.js +53 -45
  47. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
  48. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  49. package/esm/policies/PackageAllowedScopes.js +45 -40
  50. package/esm/policies/PackageAllowedScopes.js.map +1 -1
  51. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  52. package/esm/policies/PackageEsmType.js +48 -44
  53. package/esm/policies/PackageEsmType.js.map +1 -1
  54. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  55. package/esm/policies/PackageFolderName.js +38 -34
  56. package/esm/policies/PackageFolderName.js.map +1 -1
  57. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  58. package/esm/policies/PackageJsonProperties.js +36 -31
  59. package/esm/policies/PackageJsonProperties.js.map +1 -1
  60. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  61. package/esm/policies/PackageJsonRepoDirectoryProperty.js +41 -38
  62. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  63. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  64. package/esm/policies/PackageJsonSorted.js +40 -36
  65. package/esm/policies/PackageJsonSorted.js.map +1 -1
  66. package/esm/policies/PackageLicense.d.ts.map +1 -1
  67. package/esm/policies/PackageLicense.js +58 -54
  68. package/esm/policies/PackageLicense.js.map +1 -1
  69. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  70. package/esm/policies/PackagePrivateField.js +58 -54
  71. package/esm/policies/PackagePrivateField.js.map +1 -1
  72. package/esm/policies/PackageReadme.d.ts.map +1 -1
  73. package/esm/policies/PackageReadme.js +30 -26
  74. package/esm/policies/PackageReadme.js.map +1 -1
  75. package/esm/policies/PackageScripts.d.ts.map +1 -1
  76. package/esm/policies/PackageScripts.js +39 -35
  77. package/esm/policies/PackageScripts.js.map +1 -1
  78. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  79. package/esm/policies/PackageTestScripts.js +46 -40
  80. package/esm/policies/PackageTestScripts.js.map +1 -1
  81. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  82. package/esm/policies/RequiredGitignorePatterns.js +20 -15
  83. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  84. package/esm/policy.d.ts +32 -7
  85. package/esm/policy.d.ts.map +1 -1
  86. package/esm/policy.js +18 -9
  87. package/esm/policy.js.map +1 -1
  88. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +43 -1
  89. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  90. package/esm/policyDefiners/defineFileHeaderPolicy.js +16 -4
  91. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  92. package/esm/policyDefiners/definePackagePolicy.d.ts +43 -2
  93. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  94. package/esm/policyDefiners/definePackagePolicy.js +40 -5
  95. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  96. package/esm/tsdoc-metadata.json +1 -1
  97. package/oclif.manifest.json +1 -1
  98. package/package.json +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"PackageFolderName.js","sourceRoot":"","sources":["../../src/policies/PackageFolderName.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,SAAS,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAgE3D;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAa,EAAE,WAAqB;IAC7D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAC7B,WAAmB,EACnB,WAAqB;IAErB,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE9D,gEAAgE;IAChE,IAAI,KAAK,KAAK,SAAS,IAAI,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QACjE,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,8EAA8E;IAC9E,OAAO,WAAW,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAGlD,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACvD,2DAA2D;IAC3D,MAAM,eAAe,GAAG,MAAM,IAAI,EAAE,CAAC;IAErC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;IAE9B,+BAA+B;IAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,8CAA8C;IAC9C,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,oCAAoC;IACpC,IAAI,eAAe,CAAC,eAAe,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC;IACb,CAAC;IAED,yDAAyD;IACzD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAErD,+BAA+B;IAC/B,MAAM,kBAAkB,GAAG,qBAAqB,CAC/C,WAAW,EACX,eAAe,CAAC,WAAW,IAAI,EAAE,CACjC,CAAC;IAEF,uCAAuC;IACvC,IAAI,UAAU,KAAK,kBAAkB,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,iBAAiB,CAAC,IAAI;QAC5B,IAAI;QACJ,WAAW,EAAE,KAAK,EAAE,8BAA8B;QAClD,aAAa,EAAE;YACd,mBAAmB,UAAU,kCAAkC,WAAW,6BAA6B,kBAAkB,GAAG;SAC5H;KACD,CAAC;IACF,OAAO,UAAU,CAAC;AACnB,CAAC,CAAC,CAAC","sourcesContent":["import path from \"pathe\";\nimport picomatch from \"picomatch\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\nimport { parsePackageName } from \"../utils/packageName.js\";\n\n/**\n * Configuration for the PackageFolderName policy.\n *\n * This policy ensures that package folder names match their package names,\n * promoting consistency and making packages easier to find in the file system.\n *\n * @example\n * ```typescript\n * const config: PackageFolderNameConfig = {\n * // Strip all scopes when matching folder names\n * stripScopes: [\"@*\"],\n * // Or strip specific scopes\n * stripScopes: [\"@myorg\", \"@internal\"],\n * // These packages are exempt from the check\n * excludePackages: [\"@myorg/special-name\"],\n * };\n * ```\n *\n * @alpha\n */\nexport interface PackageFolderNameConfig {\n\t/**\n\t * A list of npm scope patterns to strip when comparing folder names to package names.\n\t *\n\t * For scoped packages like `@myorg/my-package`, if `@myorg` matches a pattern in this list,\n\t * the policy will expect the folder to be named `my-package` (not `@myorg/my-package`).\n\t *\n\t * @remarks\n\t *\n\t * Supports glob patterns:\n\t * - `@*` - matches all scopes\n\t * - `@myorg` - matches exactly `@myorg`\n\t * - `@my*` - matches scopes starting with `@my`\n\t *\n\t * @example\n\t * ```typescript\n\t * // Strip all scopes - @anything/my-package → folder \"my-package\"\n\t * stripScopes: [\"@*\"]\n\t *\n\t * // Strip specific scopes only\n\t * stripScopes: [\"@myorg\", \"@internal\"]\n\t *\n\t * // Strip scopes matching a pattern\n\t * stripScopes: [\"@fluid*\"]\n\t * ```\n\t */\n\tstripScopes?: string[];\n\n\t/**\n\t * A list of package names that are exempt from folder name matching.\n\t *\n\t * Use this for packages that intentionally have different folder names,\n\t * such as legacy packages or packages with special naming requirements.\n\t *\n\t * @example\n\t * ```typescript\n\t * excludePackages: [\"@myorg/cli\", \"legacy-package\"]\n\t * ```\n\t */\n\texcludePackages?: string[];\n}\n\n/**\n * Check if a scope should be stripped based on the patterns.\n *\n * @param scope - The scope to check (e.g., `@myorg`)\n * @param stripScopes - List of scope patterns to match (supports glob patterns via picomatch)\n * @returns `true` if the scope matches any pattern\n */\nfunction shouldStripScope(scope: string, stripScopes: string[]): boolean {\n\tif (stripScopes.length === 0) {\n\t\treturn false;\n\t}\n\n\treturn picomatch.isMatch(scope, stripScopes);\n}\n\n/**\n * Get the expected folder name from a package name.\n *\n * @param packageName - The package name (e.g., `@myorg/my-package`)\n * @param stripScopes - Scope patterns to strip from the package name\n * @returns The expected folder name\n */\nfunction getExpectedFolderName(\n\tpackageName: string,\n\tstripScopes: string[],\n): string {\n\tconst { scope, unscopedName } = parsePackageName(packageName);\n\n\t// Check if the package is scoped and should have scope stripped\n\tif (scope !== undefined && shouldStripScope(scope, stripScopes)) {\n\t\treturn unscopedName;\n\t}\n\n\t// Return full package name for unscoped packages or scopes not in stripScopes\n\treturn packageName;\n}\n\n/**\n * A policy that ensures package folder names match package names.\n *\n * This policy helps maintain a consistent and predictable file structure\n * in monorepos by ensuring that folder names correspond to package names.\n * This makes it easier to locate packages in the file system.\n *\n * @remarks\n *\n * The policy compares the immediate parent folder name of the package.json\n * against the package name. For scoped packages, the scope can optionally\n * be stripped based on the `stripScopes` configuration.\n *\n * For example:\n * - `packages/my-lib/package.json` with name `my-lib` ✓\n * - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if @myorg in stripScopes)\n * - `packages/wrong-name/package.json` with name `my-lib` ✗\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageFolderName } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * makePolicy(PackageFolderName, {\n * stripScopes: [\"@myorg\", \"@internal\"],\n * excludePackages: [\"@myorg/special-case\"],\n * }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageFolderName = definePackagePolicy<\n\tPackageJson,\n\tPackageFolderNameConfig | undefined\n>(\"PackageFolderName\", async (json, { file, config }) => {\n\t// If no config provided, use defaults (check all packages)\n\tconst effectiveConfig = config ?? {};\n\n\tconst packageName = json.name;\n\n\t// Skip packages without a name\n\tif (packageName === undefined) {\n\t\treturn true;\n\t}\n\n\t// Skip the root package (common in monorepos)\n\tif (packageName === \"root\") {\n\t\treturn true;\n\t}\n\n\t// Skip explicitly excluded packages\n\tif (effectiveConfig.excludePackages?.includes(packageName)) {\n\t\treturn true;\n\t}\n\n\t// Get the folder name (parent directory of package.json)\n\tconst folderName = path.basename(path.dirname(file));\n\n\t// Get the expected folder name\n\tconst expectedFolderName = getExpectedFolderName(\n\t\tpackageName,\n\t\teffectiveConfig.stripScopes ?? [],\n\t);\n\n\t// Compare folder name to expected name\n\tif (folderName === expectedFolderName) {\n\t\treturn true;\n\t}\n\n\t// Mismatch - build error message\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageFolderName.name,\n\t\tfile,\n\t\tautoFixable: false, // Can't auto-fix folder names\n\t\terrorMessages: [\n\t\t\t`Package folder \"${folderName}\" does not match package name \"${packageName}\". Expected folder name: \"${expectedFolderName}\"`,\n\t\t],\n\t};\n\treturn failResult;\n});\n"]}
1
+ {"version":3,"file":"PackageFolderName.js","sourceRoot":"","sources":["../../src/policies/PackageFolderName.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,SAAS,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAgE3D;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAa,EAAE,WAAqB;IAC7D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAC7B,WAAmB,EACnB,WAAqB;IAErB,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE9D,gEAAgE;IAChE,IAAI,KAAK,KAAK,SAAS,IAAI,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QACjE,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,8EAA8E;IAC9E,OAAO,WAAW,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAGlD;IACD,IAAI,EAAE,mBAAmB;IACzB,WAAW,EACV,iFAAiF;IAClF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QACzC,2DAA2D;QAC3D,MAAM,eAAe,GAAG,MAAM,IAAI,EAAE,CAAC;QAErC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;QAE9B,+BAA+B;QAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,8CAA8C;QAC9C,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,oCAAoC;QACpC,IAAI,eAAe,CAAC,eAAe,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACb,CAAC;QAED,yDAAyD;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAErD,+BAA+B;QAC/B,MAAM,kBAAkB,GAAG,qBAAqB,CAC/C,WAAW,EACX,eAAe,CAAC,WAAW,IAAI,EAAE,CACjC,CAAC;QAEF,uCAAuC;QACvC,IAAI,UAAU,KAAK,kBAAkB,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,iCAAiC;QACjC,MAAM,UAAU,GAAkB;YACjC,IAAI,EAAE,iBAAiB,CAAC,IAAI;YAC5B,IAAI;YACJ,WAAW,EAAE,KAAK,EAAE,8BAA8B;YAClD,aAAa,EAAE;gBACd,mBAAmB,UAAU,kCAAkC,WAAW,6BAA6B,kBAAkB,GAAG;aAC5H;SACD,CAAC;QACF,OAAO,UAAU,CAAC;IACnB,CAAC;CACD,CAAC,CAAC","sourcesContent":["import path from \"pathe\";\nimport picomatch from \"picomatch\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\nimport { parsePackageName } from \"../utils/packageName.js\";\n\n/**\n * Configuration for the PackageFolderName policy.\n *\n * This policy ensures that package folder names match their package names,\n * promoting consistency and making packages easier to find in the file system.\n *\n * @example\n * ```typescript\n * const config: PackageFolderNameConfig = {\n * // Strip all scopes when matching folder names\n * stripScopes: [\"@*\"],\n * // Or strip specific scopes\n * stripScopes: [\"@myorg\", \"@internal\"],\n * // These packages are exempt from the check\n * excludePackages: [\"@myorg/special-name\"],\n * };\n * ```\n *\n * @alpha\n */\nexport interface PackageFolderNameConfig {\n\t/**\n\t * A list of npm scope patterns to strip when comparing folder names to package names.\n\t *\n\t * For scoped packages like `@myorg/my-package`, if `@myorg` matches a pattern in this list,\n\t * the policy will expect the folder to be named `my-package` (not `@myorg/my-package`).\n\t *\n\t * @remarks\n\t *\n\t * Supports glob patterns:\n\t * - `@*` - matches all scopes\n\t * - `@myorg` - matches exactly `@myorg`\n\t * - `@my*` - matches scopes starting with `@my`\n\t *\n\t * @example\n\t * ```typescript\n\t * // Strip all scopes - @anything/my-package → folder \"my-package\"\n\t * stripScopes: [\"@*\"]\n\t *\n\t * // Strip specific scopes only\n\t * stripScopes: [\"@myorg\", \"@internal\"]\n\t *\n\t * // Strip scopes matching a pattern\n\t * stripScopes: [\"@fluid*\"]\n\t * ```\n\t */\n\tstripScopes?: string[];\n\n\t/**\n\t * A list of package names that are exempt from folder name matching.\n\t *\n\t * Use this for packages that intentionally have different folder names,\n\t * such as legacy packages or packages with special naming requirements.\n\t *\n\t * @example\n\t * ```typescript\n\t * excludePackages: [\"@myorg/cli\", \"legacy-package\"]\n\t * ```\n\t */\n\texcludePackages?: string[];\n}\n\n/**\n * Check if a scope should be stripped based on the patterns.\n *\n * @param scope - The scope to check (e.g., `@myorg`)\n * @param stripScopes - List of scope patterns to match (supports glob patterns via picomatch)\n * @returns `true` if the scope matches any pattern\n */\nfunction shouldStripScope(scope: string, stripScopes: string[]): boolean {\n\tif (stripScopes.length === 0) {\n\t\treturn false;\n\t}\n\n\treturn picomatch.isMatch(scope, stripScopes);\n}\n\n/**\n * Get the expected folder name from a package name.\n *\n * @param packageName - The package name (e.g., `@myorg/my-package`)\n * @param stripScopes - Scope patterns to strip from the package name\n * @returns The expected folder name\n */\nfunction getExpectedFolderName(\n\tpackageName: string,\n\tstripScopes: string[],\n): string {\n\tconst { scope, unscopedName } = parsePackageName(packageName);\n\n\t// Check if the package is scoped and should have scope stripped\n\tif (scope !== undefined && shouldStripScope(scope, stripScopes)) {\n\t\treturn unscopedName;\n\t}\n\n\t// Return full package name for unscoped packages or scopes not in stripScopes\n\treturn packageName;\n}\n\n/**\n * A policy that ensures package folder names match package names.\n *\n * This policy helps maintain a consistent and predictable file structure\n * in monorepos by ensuring that folder names correspond to package names.\n * This makes it easier to locate packages in the file system.\n *\n * @remarks\n *\n * The policy compares the immediate parent folder name of the package.json\n * against the package name. For scoped packages, the scope can optionally\n * be stripped based on the `stripScopes` configuration.\n *\n * For example:\n * - `packages/my-lib/package.json` with name `my-lib` ✓\n * - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if @myorg in stripScopes)\n * - `packages/wrong-name/package.json` with name `my-lib` ✗\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageFolderName } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * makePolicy(PackageFolderName, {\n * stripScopes: [\"@myorg\", \"@internal\"],\n * excludePackages: [\"@myorg/special-case\"],\n * }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageFolderName = definePackagePolicy<\n\tPackageJson,\n\tPackageFolderNameConfig | undefined\n>({\n\tname: \"PackageFolderName\",\n\tdescription:\n\t\t\"Ensures package folder names match package names for consistent file structure.\",\n\thandler: async (json, { file, config }) => {\n\t\t// If no config provided, use defaults (check all packages)\n\t\tconst effectiveConfig = config ?? {};\n\n\t\tconst packageName = json.name;\n\n\t\t// Skip packages without a name\n\t\tif (packageName === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Skip the root package (common in monorepos)\n\t\tif (packageName === \"root\") {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Skip explicitly excluded packages\n\t\tif (effectiveConfig.excludePackages?.includes(packageName)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Get the folder name (parent directory of package.json)\n\t\tconst folderName = path.basename(path.dirname(file));\n\n\t\t// Get the expected folder name\n\t\tconst expectedFolderName = getExpectedFolderName(\n\t\t\tpackageName,\n\t\t\teffectiveConfig.stripScopes ?? [],\n\t\t);\n\n\t\t// Compare folder name to expected name\n\t\tif (folderName === expectedFolderName) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Mismatch - build error message\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageFolderName.name,\n\t\t\tfile,\n\t\t\tautoFixable: false, // Can't auto-fix folder names\n\t\t\terrorMessages: [\n\t\t\t\t`Package folder \"${folderName}\" does not match package name \"${packageName}\". Expected folder name: \"${expectedFolderName}\"`,\n\t\t\t],\n\t\t};\n\t\treturn failResult;\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonProperties.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM7C;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC7C;;OAEG;IACH,QAAQ,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oFA6ChC,CAAC"}
1
+ {"version":3,"file":"PackageJsonProperties.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM7C;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC7C;;OAEG;IACH,QAAQ,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oFAkDhC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { defu } from "defu";
2
+ import { call } from "effection";
2
3
  import jsonfile from "jsonfile";
3
4
  import diff from "microdiff";
4
5
  import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
@@ -8,37 +9,41 @@ const { writeFile: writeJson } = jsonfile;
8
9
  *
9
10
  * @alpha
10
11
  */
11
- export const PackageJsonProperties = definePackagePolicy("PackageJsonProperties", async (json, { file, config, resolve }) => {
12
- if (config === undefined) {
13
- return true;
14
- }
15
- const { verbatim } = config;
16
- const failResult = {
17
- name: PackageJsonProperties.name,
18
- file,
19
- autoFixable: true,
20
- errorMessages: [],
21
- };
22
- const merged = defu(verbatim, json);
23
- const result = diff(merged, json);
24
- const messages = [];
25
- for (const diffResult of result) {
26
- messages.push(`Incorrect package.json field value for '${diffResult.path}'.`);
27
- }
28
- if (messages.length > 0) {
29
- if (resolve) {
30
- const fixResult = {
31
- ...failResult,
32
- resolved: false,
33
- };
34
- await writeJson(file, merged, { spaces: "\t" });
35
- fixResult.resolved = true;
36
- return fixResult;
12
+ export const PackageJsonProperties = definePackagePolicy({
13
+ name: "PackageJsonProperties",
14
+ description: "Ensures package.json files contain required properties with correct values.",
15
+ handler: function* (json, { file, config, resolve }) {
16
+ if (config === undefined) {
17
+ return true;
18
+ }
19
+ const { verbatim } = config;
20
+ const failResult = {
21
+ name: PackageJsonProperties.name,
22
+ file,
23
+ autoFixable: true,
24
+ errorMessages: [],
25
+ };
26
+ const merged = defu(verbatim, json);
27
+ const result = diff(merged, json);
28
+ const messages = [];
29
+ for (const diffResult of result) {
30
+ messages.push(`Incorrect package.json field value for '${diffResult.path}'.`);
37
31
  }
38
- // There were errors, and we're not resolving them, so return a fail result
39
- failResult.errorMessages = messages;
40
- return failResult;
41
- }
42
- return true;
32
+ if (messages.length > 0) {
33
+ if (resolve) {
34
+ const fixResult = {
35
+ ...failResult,
36
+ resolved: false,
37
+ };
38
+ yield* call(() => writeJson(file, merged, { spaces: "\t" }));
39
+ fixResult.resolved = true;
40
+ return fixResult;
41
+ }
42
+ // There were errors, and we're not resolving them, so return a fail result
43
+ failResult.errorMessages = messages;
44
+ return failResult;
45
+ }
46
+ return true;
47
+ },
43
48
  });
44
49
  //# sourceMappingURL=PackageJsonProperties.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonProperties.js","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC;AAc1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAGtD,uBAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,qBAAqB,CAAC,IAAI;QAChC,IAAI;QACJ,WAAW,EAAE,IAAI;QACjB,aAAa,EAAE,EAAE;KACjB,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,IAAI,CACZ,2CAA2C,UAAU,CAAC,IAAI,IAAI,CAC9D,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAoB;gBAClC,GAAG,UAAU;gBACb,QAAQ,EAAE,KAAK;aACf,CAAC;YAEF,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAEhD,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC1B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,2EAA2E;QAC3E,UAAU,CAAC,aAAa,GAAG,QAAQ,CAAC;QACpC,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import { defu } from \"defu\";\nimport jsonfile from \"jsonfile\";\nimport diff from \"microdiff\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Policy settings for the PackageJsonProperties repo policy.\n *\n * @alpha\n */\nexport interface PackageJsonPropertiesSettings {\n\t/**\n\t * Sets a package.json property to the value provided. The value will be used verbatim.\n\t */\n\tverbatim: PackageJson;\n}\n\n/**\n * A RepoPolicy that checks that package.json properties in packages match expected values.\n *\n * @alpha\n */\nexport const PackageJsonProperties = definePackagePolicy<\n\tPackageJson,\n\tPackageJsonPropertiesSettings | undefined\n>(\"PackageJsonProperties\", async (json, { file, config, resolve }) => {\n\tif (config === undefined) {\n\t\treturn true;\n\t}\n\tconst { verbatim } = config;\n\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonProperties.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t\terrorMessages: [],\n\t};\n\n\tconst merged = defu(verbatim, json);\n\tconst result = diff(merged, json);\n\n\tconst messages: string[] = [];\n\tfor (const diffResult of result) {\n\t\tmessages.push(\n\t\t\t`Incorrect package.json field value for '${diffResult.path}'.`,\n\t\t);\n\t}\n\n\tif (messages.length > 0) {\n\t\tif (resolve) {\n\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t...failResult,\n\t\t\t\tresolved: false,\n\t\t\t};\n\n\t\t\tawait writeJson(file, merged, { spaces: \"\\t\" });\n\n\t\t\tfixResult.resolved = true;\n\t\t\treturn fixResult;\n\t\t}\n\n\t\t// There were errors, and we're not resolving them, so return a fail result\n\t\tfailResult.errorMessages = messages;\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
1
+ {"version":3,"file":"PackageJsonProperties.js","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC;AAc1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAGtD;IACD,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACV,6EAA6E;IAC9E,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAClD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACb,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;QAE5B,MAAM,UAAU,GAAkB;YACjC,IAAI,EAAE,qBAAqB,CAAC,IAAI;YAChC,IAAI;YACJ,WAAW,EAAE,IAAI;YACjB,aAAa,EAAE,EAAE;SACjB,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAElC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CACZ,2CAA2C,UAAU,CAAC,IAAI,IAAI,CAC9D,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,OAAO,EAAE,CAAC;gBACb,MAAM,SAAS,GAAoB;oBAClC,GAAG,UAAU;oBACb,QAAQ,EAAE,KAAK;iBACf,CAAC;gBAEF,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAE7D,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC1B,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,2EAA2E;YAC3E,UAAU,CAAC,aAAa,GAAG,QAAQ,CAAC;YACpC,OAAO,UAAU,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC,CAAC","sourcesContent":["import { defu } from \"defu\";\nimport { call } from \"effection\";\nimport jsonfile from \"jsonfile\";\nimport diff from \"microdiff\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Policy settings for the PackageJsonProperties repo policy.\n *\n * @alpha\n */\nexport interface PackageJsonPropertiesSettings {\n\t/**\n\t * Sets a package.json property to the value provided. The value will be used verbatim.\n\t */\n\tverbatim: PackageJson;\n}\n\n/**\n * A RepoPolicy that checks that package.json properties in packages match expected values.\n *\n * @alpha\n */\nexport const PackageJsonProperties = definePackagePolicy<\n\tPackageJson,\n\tPackageJsonPropertiesSettings | undefined\n>({\n\tname: \"PackageJsonProperties\",\n\tdescription:\n\t\t\"Ensures package.json files contain required properties with correct values.\",\n\thandler: function* (json, { file, config, resolve }) {\n\t\tif (config === undefined) {\n\t\t\treturn true;\n\t\t}\n\t\tconst { verbatim } = config;\n\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageJsonProperties.name,\n\t\t\tfile,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [],\n\t\t};\n\n\t\tconst merged = defu(verbatim, json);\n\t\tconst result = diff(merged, json);\n\n\t\tconst messages: string[] = [];\n\t\tfor (const diffResult of result) {\n\t\t\tmessages.push(\n\t\t\t\t`Incorrect package.json field value for '${diffResult.path}'.`,\n\t\t\t);\n\t\t}\n\n\t\tif (messages.length > 0) {\n\t\t\tif (resolve) {\n\t\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t\t...failResult,\n\t\t\t\t\tresolved: false,\n\t\t\t\t};\n\n\t\t\t\tyield* call(() => writeJson(file, merged, { spaces: \"\\t\" }));\n\n\t\t\t\tfixResult.resolved = true;\n\t\t\t\treturn fixResult;\n\t\t\t}\n\n\t\t\t// There were errors, and we're not resolving them, so return a fail result\n\t\t\tfailResult.errorMessages = messages;\n\t\t\treturn failResult;\n\t\t}\n\n\t\treturn true;\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonRepoDirectoryProperty.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,oDAmD3C,CAAC"}
1
+ {"version":3,"file":"PackageJsonRepoDirectoryProperty.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,oDAuD3C,CAAC"}
@@ -8,45 +8,48 @@ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
8
8
  *
9
9
  * @alpha
10
10
  */
11
- export const PackageJsonRepoDirectoryProperty = definePackagePolicy("PackageJsonRepoDirectoryProperty", async (json, { file, root, resolve }) => {
12
- const failResult = {
13
- name: PackageJsonRepoDirectoryProperty.name,
14
- file,
15
- autoFixable: true,
16
- errorMessages: [],
17
- };
18
- const fixResult = {
19
- ...failResult,
20
- resolved: false,
21
- };
22
- const pkgDir = path.dirname(path.resolve(root, file));
23
- const maybeDir = path.relative(root, pkgDir);
24
- const relativePkgDir = maybeDir === "" ? undefined : maybeDir;
25
- if (typeof json.repository === "object" &&
26
- json.repository.directory !== relativePkgDir) {
27
- if (resolve) {
28
- try {
29
- // biome-ignore lint/nursery/noShadow: no need to use shadowed variable
30
- updatePackageJsonFile(file, (json) => {
31
- assert(typeof json.repository === "object");
32
- if (relativePkgDir === undefined) {
33
- delete json.repository.directory;
34
- }
35
- else {
36
- json.repository.directory = relativePkgDir;
37
- }
38
- });
39
- fixResult.resolved = true;
11
+ export const PackageJsonRepoDirectoryProperty = definePackagePolicy({
12
+ name: "PackageJsonRepoDirectoryProperty",
13
+ description: "Ensures the repository.directory property in package.json is set correctly for monorepo packages.",
14
+ handler: function* (json, { file, root, resolve }) {
15
+ const failResult = {
16
+ name: PackageJsonRepoDirectoryProperty.name,
17
+ file,
18
+ autoFixable: true,
19
+ errorMessages: [],
20
+ };
21
+ const fixResult = {
22
+ ...failResult,
23
+ resolved: false,
24
+ };
25
+ const pkgDir = path.dirname(file);
26
+ const maybeDir = path.relative(root, pkgDir);
27
+ const relativePkgDir = maybeDir === "" ? undefined : maybeDir;
28
+ if (typeof json.repository === "object" &&
29
+ json.repository.directory !== relativePkgDir) {
30
+ if (resolve) {
31
+ try {
32
+ updatePackageJsonFile(file, (pkgJson) => {
33
+ assert(typeof pkgJson.repository === "object");
34
+ if (relativePkgDir === undefined) {
35
+ delete pkgJson.repository.directory;
36
+ }
37
+ else {
38
+ pkgJson.repository.directory = relativePkgDir;
39
+ }
40
+ });
41
+ fixResult.resolved = true;
42
+ }
43
+ catch (error) {
44
+ fixResult.resolved = false;
45
+ fixResult.errorMessages.push(`${error.message}\n${error.stack}`);
46
+ }
47
+ return fixResult;
40
48
  }
41
- catch (error) {
42
- fixResult.resolved = false;
43
- fixResult.errorMessages.push(`${error.message}\n${error.stack}`);
44
- }
45
- return fixResult;
49
+ failResult.errorMessages.push(`repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`);
50
+ return failResult;
46
51
  }
47
- failResult.errorMessages.push(`repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`);
48
- return failResult;
49
- }
50
- return true;
52
+ return true;
53
+ },
51
54
  });
52
55
  //# sourceMappingURL=PackageJsonRepoDirectoryProperty.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonRepoDirectoryProperty.js","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,IAAI,MAAM,OAAO,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,mBAAmB,CAGjE,kCAAkC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC7E,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,gCAAgC,CAAC,IAAI;QAC3C,IAAI;QACJ,WAAW,EAAE,IAAI;QACjB,aAAa,EAAE,EAAE;KACjB,CAAC;IAEF,MAAM,SAAS,GAAoB;QAClC,GAAG,UAAU;QACb,QAAQ,EAAE,KAAK;KACf,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE9D,IACC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QACnC,IAAI,CAAC,UAAU,CAAC,SAAS,KAAK,cAAc,EAC3C,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC;gBACJ,uEAAuE;gBACvE,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBACpC,MAAM,CAAC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;oBAC5C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;wBAClC,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;oBAClC,CAAC;yBAAM,CAAC;wBACP,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,cAAc,CAAC;oBAC5C,CAAC;gBACF,CAAC,CAAC,CAAC;gBACH,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACzB,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;gBAC3B,SAAS,CAAC,aAAa,CAAC,IAAI,CAC3B,GAAI,KAAe,CAAC,OAAO,KAAM,KAAe,CAAC,KAAK,EAAE,CACxD,CAAC;YACH,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,UAAU,CAAC,aAAa,CAAC,IAAI,CAC5B,kDAAkD,cAAc,WAAW,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,CACvG,CAAC;QACF,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport { updatePackageJsonFile } from \"@fluid-tools/build-infrastructure\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A RepoPolicy that checks that the repository.directory property in package.json is set correctly. If the repository\n * field is a string instead of an object the package will be ignored.\n *\n * @alpha\n */\nexport const PackageJsonRepoDirectoryProperty = definePackagePolicy<\n\tPackageJson,\n\tundefined\n>(\"PackageJsonRepoDirectoryProperty\", async (json, { file, root, resolve }) => {\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonRepoDirectoryProperty.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t\terrorMessages: [],\n\t};\n\n\tconst fixResult: PolicyFixResult = {\n\t\t...failResult,\n\t\tresolved: false,\n\t};\n\n\tconst pkgDir = path.dirname(path.resolve(root, file));\n\tconst maybeDir = path.relative(root, pkgDir);\n\tconst relativePkgDir = maybeDir === \"\" ? undefined : maybeDir;\n\n\tif (\n\t\ttypeof json.repository === \"object\" &&\n\t\tjson.repository.directory !== relativePkgDir\n\t) {\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\t// biome-ignore lint/nursery/noShadow: no need to use shadowed variable\n\t\t\t\tupdatePackageJsonFile(file, (json) => {\n\t\t\t\t\tassert(typeof json.repository === \"object\");\n\t\t\t\t\tif (relativePkgDir === undefined) {\n\t\t\t\t\t\tdelete json.repository.directory;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tjson.repository.directory = relativePkgDir;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tfixResult.resolved = true;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tfixResult.resolved = false;\n\t\t\t\tfixResult.errorMessages.push(\n\t\t\t\t\t`${(error as Error).message}\\n${(error as Error).stack}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn fixResult;\n\t\t}\n\t\tfailResult.errorMessages.push(\n\t\t\t`repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`,\n\t\t);\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
1
+ {"version":3,"file":"PackageJsonRepoDirectoryProperty.js","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,IAAI,MAAM,OAAO,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,mBAAmB,CAGjE;IACD,IAAI,EAAE,kCAAkC;IACxC,WAAW,EACV,mGAAmG;IACpG,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChD,MAAM,UAAU,GAAkB;YACjC,IAAI,EAAE,gCAAgC,CAAC,IAAI;YAC3C,IAAI;YACJ,WAAW,EAAE,IAAI;YACjB,aAAa,EAAE,EAAE;SACjB,CAAC;QAEF,MAAM,SAAS,GAAoB;YAClC,GAAG,UAAU;YACb,QAAQ,EAAE,KAAK;SACf,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,cAAc,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;QAE9D,IACC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;YACnC,IAAI,CAAC,UAAU,CAAC,SAAS,KAAK,cAAc,EAC3C,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC;oBACJ,qBAAqB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;wBACvC,MAAM,CAAC,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;wBAC/C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;4BAClC,OAAO,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;wBACrC,CAAC;6BAAM,CAAC;4BACP,OAAO,CAAC,UAAU,CAAC,SAAS,GAAG,cAAc,CAAC;wBAC/C,CAAC;oBACF,CAAC,CAAC,CAAC;oBACH,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC3B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACzB,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;oBAC3B,SAAS,CAAC,aAAa,CAAC,IAAI,CAC3B,GAAI,KAAe,CAAC,OAAO,KAAM,KAAe,CAAC,KAAK,EAAE,CACxD,CAAC;gBACH,CAAC;gBACD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,UAAU,CAAC,aAAa,CAAC,IAAI,CAC5B,kDAAkD,cAAc,WAAW,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,CACvG,CAAC;YACF,OAAO,UAAU,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport { updatePackageJsonFile } from \"@fluid-tools/build-infrastructure\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A RepoPolicy that checks that the repository.directory property in package.json is set correctly. If the repository\n * field is a string instead of an object the package will be ignored.\n *\n * @alpha\n */\nexport const PackageJsonRepoDirectoryProperty = definePackagePolicy<\n\tPackageJson,\n\tundefined\n>({\n\tname: \"PackageJsonRepoDirectoryProperty\",\n\tdescription:\n\t\t\"Ensures the repository.directory property in package.json is set correctly for monorepo packages.\",\n\thandler: function* (json, { file, root, resolve }) {\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageJsonRepoDirectoryProperty.name,\n\t\t\tfile,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [],\n\t\t};\n\n\t\tconst fixResult: PolicyFixResult = {\n\t\t\t...failResult,\n\t\t\tresolved: false,\n\t\t};\n\n\t\tconst pkgDir = path.dirname(file);\n\t\tconst maybeDir = path.relative(root, pkgDir);\n\t\tconst relativePkgDir = maybeDir === \"\" ? undefined : maybeDir;\n\n\t\tif (\n\t\t\ttypeof json.repository === \"object\" &&\n\t\t\tjson.repository.directory !== relativePkgDir\n\t\t) {\n\t\t\tif (resolve) {\n\t\t\t\ttry {\n\t\t\t\t\tupdatePackageJsonFile(file, (pkgJson) => {\n\t\t\t\t\t\tassert(typeof pkgJson.repository === \"object\");\n\t\t\t\t\t\tif (relativePkgDir === undefined) {\n\t\t\t\t\t\t\tdelete pkgJson.repository.directory;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpkgJson.repository.directory = relativePkgDir;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tfixResult.resolved = true;\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tfixResult.resolved = false;\n\t\t\t\t\tfixResult.errorMessages.push(\n\t\t\t\t\t\t`${(error as Error).message}\\n${(error as Error).stack}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn fixResult;\n\t\t\t}\n\t\t\tfailResult.errorMessages.push(\n\t\t\t\t`repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`,\n\t\t\t);\n\t\t\treturn failResult;\n\t\t}\n\n\t\treturn true;\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonSorted.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oDA8C7B,CAAC"}
1
+ {"version":3,"file":"PackageJsonSorted.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oDAiD5B,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { updatePackageJsonFile } from "@tylerbu/cli-api";
2
- import { join } from "pathe";
2
+ import { call } from "effection";
3
+ import { resolve as resolvePath } from "pathe";
3
4
  import { sortPackageJson } from "sort-package-json";
4
5
  import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
5
6
  /**
@@ -7,48 +8,51 @@ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
7
8
  *
8
9
  * @alpha
9
10
  */
10
- export const PackageJsonSorted = definePackagePolicy("PackageJsonSorted", async (json, { file, root, resolve }) => {
11
- const sortedJson = sortPackageJson(json);
12
- const isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);
13
- if (isSorted) {
14
- return true;
15
- }
16
- if (resolve) {
17
- try {
18
- // biome-ignore lint/nursery/noShadow: no need to use the shadowed variable
19
- await updatePackageJsonFile(join(root, file), (json) => json, {
20
- sort: true,
21
- });
22
- const result = {
23
- name: PackageJsonSorted.name,
24
- file,
25
- resolved: true,
26
- errorMessages: [],
27
- };
28
- return result;
11
+ export const PackageJsonSorted = definePackagePolicy({
12
+ name: "PackageJsonSorted",
13
+ description: "Ensures package.json files are sorted consistently using sort-package-json.",
14
+ handler: function* (json, { file, root, resolve }) {
15
+ const sortedJson = sortPackageJson(json);
16
+ const isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);
17
+ if (isSorted) {
18
+ return true;
29
19
  }
30
- catch (error) {
20
+ if (resolve) {
21
+ try {
22
+ yield* call(() => updatePackageJsonFile(resolvePath(root, file), (pkgJson) => pkgJson, {
23
+ sort: true,
24
+ }));
25
+ const result = {
26
+ name: PackageJsonSorted.name,
27
+ file,
28
+ resolved: true,
29
+ errorMessages: [],
30
+ };
31
+ return result;
32
+ }
33
+ catch (error) {
34
+ const result = {
35
+ name: PackageJsonSorted.name,
36
+ file,
37
+ resolved: false,
38
+ autoFixable: true,
39
+ errorMessages: [
40
+ error.message,
41
+ error.stack ?? "",
42
+ ],
43
+ };
44
+ return result;
45
+ }
46
+ }
47
+ else {
31
48
  const result = {
32
49
  name: PackageJsonSorted.name,
33
50
  file,
34
- resolved: false,
35
51
  autoFixable: true,
36
- errorMessages: [
37
- error.message,
38
- error.stack ?? "",
39
- ],
52
+ errorMessages: [],
40
53
  };
41
54
  return result;
42
55
  }
43
- }
44
- else {
45
- const result = {
46
- name: PackageJsonSorted.name,
47
- file,
48
- autoFixable: true,
49
- errorMessages: [],
50
- };
51
- return result;
52
- }
56
+ },
53
57
  });
54
58
  //# sourceMappingURL=PackageJsonSorted.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonSorted.js","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CACnD,mBAAmB,EACnB,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAErE,IAAI,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,2EAA2E;YAC3E,MAAM,qBAAqB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;gBAC7D,IAAI,EAAE,IAAI;aACV,CAAC,CAAC;YACH,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,IAAI;gBACd,aAAa,EAAE,EAAE;aACjB,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE;oBACb,KAAe,CAAC,OAAO;oBACvB,KAAe,CAAC,KAAK,IAAI,EAAE;iBAC5B;aACD,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAkB;YAC7B,IAAI,EAAE,iBAAiB,CAAC,IAAI;YAC5B,IAAI;YACJ,WAAW,EAAE,IAAI;YACjB,aAAa,EAAE,EAAE;SACjB,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;AACF,CAAC,CACD,CAAC","sourcesContent":["import { updatePackageJsonFile } from \"@tylerbu/cli-api\";\nimport { join } from \"pathe\";\nimport { sortPackageJson } from \"sort-package-json\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A repo policy that checks if package.json files in the repo are sorted using sort-package-json.\n *\n * @alpha\n */\nexport const PackageJsonSorted = definePackagePolicy(\n\t\"PackageJsonSorted\",\n\tasync (json, { file, root, resolve }) => {\n\t\tconst sortedJson = sortPackageJson(json);\n\t\tconst isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);\n\n\t\tif (isSorted) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\t// biome-ignore lint/nursery/noShadow: no need to use the shadowed variable\n\t\t\t\tawait updatePackageJsonFile(join(root, file), (json) => json, {\n\t\t\t\t\tsort: true,\n\t\t\t\t});\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: true,\n\t\t\t\t\terrorMessages: [],\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: false,\n\t\t\t\t\tautoFixable: true,\n\t\t\t\t\terrorMessages: [\n\t\t\t\t\t\t(error as Error).message,\n\t\t\t\t\t\t(error as Error).stack ?? \"\",\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else {\n\t\t\tconst result: PolicyFailure = {\n\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [],\n\t\t\t};\n\t\t\treturn result;\n\t\t}\n\t},\n);\n"]}
1
+ {"version":3,"file":"PackageJsonSorted.js","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;IACpD,IAAI,EAAE,mBAAmB;IACzB,WAAW,EACV,6EAA6E;IAC9E,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChD,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAErE,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC;gBACJ,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAChB,qBAAqB,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;oBACpE,IAAI,EAAE,IAAI;iBACV,CAAC,CACF,CAAC;gBACF,MAAM,MAAM,GAAoB;oBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;oBAC5B,IAAI;oBACJ,QAAQ,EAAE,IAAI;oBACd,aAAa,EAAE,EAAE;iBACjB,CAAC;gBACF,OAAO,MAAM,CAAC;YACf,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACzB,MAAM,MAAM,GAAoB;oBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;oBAC5B,IAAI;oBACJ,QAAQ,EAAE,KAAK;oBACf,WAAW,EAAE,IAAI;oBACjB,aAAa,EAAE;wBACb,KAAe,CAAC,OAAO;wBACvB,KAAe,CAAC,KAAK,IAAI,EAAE;qBAC5B;iBACD,CAAC;gBACF,OAAO,MAAM,CAAC;YACf,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,MAAM,GAAkB;gBAC7B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,EAAE;aACjB,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;CACD,CAAC,CAAC","sourcesContent":["import { updatePackageJsonFile } from \"@tylerbu/cli-api\";\nimport { call } from \"effection\";\nimport { resolve as resolvePath } from \"pathe\";\nimport { sortPackageJson } from \"sort-package-json\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A repo policy that checks if package.json files in the repo are sorted using sort-package-json.\n *\n * @alpha\n */\nexport const PackageJsonSorted = definePackagePolicy({\n\tname: \"PackageJsonSorted\",\n\tdescription:\n\t\t\"Ensures package.json files are sorted consistently using sort-package-json.\",\n\thandler: function* (json, { file, root, resolve }) {\n\t\tconst sortedJson = sortPackageJson(json);\n\t\tconst isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);\n\n\t\tif (isSorted) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\tyield* call(() =>\n\t\t\t\t\tupdatePackageJsonFile(resolvePath(root, file), (pkgJson) => pkgJson, {\n\t\t\t\t\t\tsort: true,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: true,\n\t\t\t\t\terrorMessages: [],\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: false,\n\t\t\t\t\tautoFixable: true,\n\t\t\t\t\terrorMessages: [\n\t\t\t\t\t\t(error as Error).message,\n\t\t\t\t\t\t(error as Error).stack ?? \"\",\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else {\n\t\t\tconst result: PolicyFailure = {\n\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [],\n\t\t\t};\n\t\t\treturn result;\n\t\t}\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackageLicense.d.ts","sourceRoot":"","sources":["../../src/policies/PackageLicense.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AA8CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,cAAc,6EAoFzB,CAAC"}
1
+ {"version":3,"file":"PackageLicense.d.ts","sourceRoot":"","sources":["../../src/policies/PackageLicense.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AA8CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,cAAc,6EA0FzB,CAAC"}
@@ -71,61 +71,65 @@ async function copyLicenseFile(rootLicensePath, packageLicensePath, policyName,
71
71
  *
72
72
  * @alpha
73
73
  */
74
- export const PackageLicense = definePackagePolicy("PackageLicense", async (json, { file, root, resolve, config }) => {
75
- const skipPrivate = config?.skipPrivate ?? true;
76
- const licenseFileName = config?.licenseFileName ?? DEFAULT_LICENSE_FILE_NAME;
77
- // Skip private packages if configured to do so
78
- if (skipPrivate && json.private === true) {
79
- return true;
80
- }
81
- const packageName = json.name ?? "unknown";
82
- // file is an absolute path, get the directory containing package.json
83
- const packageDir = path.dirname(file);
84
- const packageLicensePath = path.join(packageDir, licenseFileName);
85
- const rootLicensePath = path.join(root, licenseFileName);
86
- // Check if root LICENSE exists
87
- if (!existsSync(rootLicensePath)) {
88
- return {
89
- name: POLICY_NAME,
90
- file,
91
- autoFixable: false,
92
- errorMessages: [
93
- `Cannot validate package LICENSE: root ${licenseFileName} file not found`,
94
- ],
95
- };
96
- }
97
- // Check if package LICENSE exists
98
- if (!existsSync(packageLicensePath)) {
99
- if (resolve) {
100
- return await copyLicenseFile(rootLicensePath, packageLicensePath, POLICY_NAME, file, packageName, licenseFileName, true);
74
+ export const PackageLicense = definePackagePolicy({
75
+ name: "PackageLicense",
76
+ description: "Ensures each package has a LICENSE file that matches the root repository LICENSE.",
77
+ handler: async (json, { file, root, resolve, config }) => {
78
+ const skipPrivate = config?.skipPrivate ?? true;
79
+ const licenseFileName = config?.licenseFileName ?? DEFAULT_LICENSE_FILE_NAME;
80
+ // Skip private packages if configured to do so
81
+ if (skipPrivate && json.private === true) {
82
+ return true;
101
83
  }
102
- return {
103
- name: POLICY_NAME,
104
- file,
105
- autoFixable: true,
106
- errorMessages: [
107
- `${licenseFileName} file missing for package "${packageName}"`,
108
- ],
109
- };
110
- }
111
- // Compare package LICENSE with root LICENSE
112
- const [packageLicenseContent, rootLicenseContent] = await Promise.all([
113
- readFile(packageLicensePath, "utf-8"),
114
- readFile(rootLicensePath, "utf-8"),
115
- ]);
116
- if (packageLicenseContent !== rootLicenseContent) {
117
- if (resolve) {
118
- return await copyLicenseFile(rootLicensePath, packageLicensePath, POLICY_NAME, file, packageName, licenseFileName, false);
84
+ const packageName = json.name ?? "unknown";
85
+ // file is an absolute path, get the directory containing package.json
86
+ const packageDir = path.dirname(file);
87
+ const packageLicensePath = path.join(packageDir, licenseFileName);
88
+ const rootLicensePath = path.join(root, licenseFileName);
89
+ // Check if root LICENSE exists
90
+ if (!existsSync(rootLicensePath)) {
91
+ return {
92
+ name: POLICY_NAME,
93
+ file,
94
+ autoFixable: false,
95
+ errorMessages: [
96
+ `Cannot validate package LICENSE: root ${licenseFileName} file not found`,
97
+ ],
98
+ };
119
99
  }
120
- return {
121
- name: POLICY_NAME,
122
- file,
123
- autoFixable: true,
124
- errorMessages: [
125
- `${licenseFileName} file in package "${packageName}" doesn't match root ${licenseFileName}`,
126
- ],
127
- };
128
- }
129
- return true;
100
+ // Check if package LICENSE exists
101
+ if (!existsSync(packageLicensePath)) {
102
+ if (resolve) {
103
+ return await copyLicenseFile(rootLicensePath, packageLicensePath, POLICY_NAME, file, packageName, licenseFileName, true);
104
+ }
105
+ return {
106
+ name: POLICY_NAME,
107
+ file,
108
+ autoFixable: true,
109
+ errorMessages: [
110
+ `${licenseFileName} file missing for package "${packageName}"`,
111
+ ],
112
+ };
113
+ }
114
+ // Compare package LICENSE with root LICENSE
115
+ const [packageLicenseContent, rootLicenseContent] = await Promise.all([
116
+ readFile(packageLicensePath, "utf-8"),
117
+ readFile(rootLicensePath, "utf-8"),
118
+ ]);
119
+ if (packageLicenseContent !== rootLicenseContent) {
120
+ if (resolve) {
121
+ return await copyLicenseFile(rootLicensePath, packageLicensePath, POLICY_NAME, file, packageName, licenseFileName, false);
122
+ }
123
+ return {
124
+ name: POLICY_NAME,
125
+ file,
126
+ autoFixable: true,
127
+ errorMessages: [
128
+ `${licenseFileName} file in package "${packageName}" doesn't match root ${licenseFileName}`,
129
+ ],
130
+ };
131
+ }
132
+ return true;
133
+ },
130
134
  });
131
135
  //# sourceMappingURL=PackageLicense.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageLicense.js","sourceRoot":"","sources":["../../src/policies/PackageLicense.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { copyFile, readFile } from \"node:fs/promises\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Policy settings for the PackageLicense repo policy.\n *\n * @alpha\n */\nexport interface PackageLicenseSettings {\n\t/**\n\t * Whether to skip validation for private packages.\n\t *\n\t * @defaultValue true\n\t *\n\t * @remarks\n\t *\n\t * Private packages (those with `private: true` in package.json) are typically\n\t * not published and may not need a LICENSE file. Set to `false` to require\n\t * LICENSE files for all packages.\n\t */\n\tskipPrivate?: boolean;\n\n\t/**\n\t * The name of the LICENSE file to look for and sync.\n\t *\n\t * @defaultValue \"LICENSE\"\n\t */\n\tlicenseFileName?: string;\n}\n\nconst DEFAULT_LICENSE_FILE_NAME = \"LICENSE\";\nconst POLICY_NAME = \"PackageLicense\";\n\n/**\n * Copies the root LICENSE file to the package directory.\n * @returns A PolicyFixResult indicating success or failure.\n */\nasync function copyLicenseFile(\n\trootLicensePath: string,\n\tpackageLicensePath: string,\n\tpolicyName: string,\n\tfile: string,\n\tpackageName: string,\n\tlicenseFileName: string,\n\tisCreate: boolean,\n): Promise<PolicyFixResult> {\n\ttry {\n\t\tawait copyFile(rootLicensePath, packageLicensePath);\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\tresolved: true,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\tisCreate\n\t\t\t\t\t? `Created ${licenseFileName} file for package \"${packageName}\"`\n\t\t\t\t\t: `Updated ${licenseFileName} file for package \"${packageName}\" to match root`,\n\t\t\t],\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\tresolved: false,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\tisCreate\n\t\t\t\t\t? `Failed to copy ${licenseFileName} to package \"${packageName}\"`\n\t\t\t\t\t: `Failed to update ${licenseFileName} for package \"${packageName}\"`,\n\t\t\t],\n\t\t};\n\t}\n}\n\n/**\n * A repo policy that ensures each package has a LICENSE file that matches the root LICENSE.\n *\n * @remarks\n *\n * This policy is essential for monorepos where individual packages are published\n * to npm. Each published package should include a LICENSE file, and it should\n * match the root repository's LICENSE to ensure consistent licensing.\n *\n * The policy:\n * 1. Checks if a LICENSE file exists in the package directory\n * 2. Compares it with the root LICENSE file\n * 3. Can auto-fix by copying the root LICENSE to the package directory\n *\n * By default, private packages are skipped since they're not published.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageLicense } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * // Use defaults (skip private, look for LICENSE)\n * makePolicy(PackageLicense),\n *\n * // Or require LICENSE for all packages including private\n * makePolicy(PackageLicense, { skipPrivate: false }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageLicense = definePackagePolicy<\n\tPackageJson,\n\tPackageLicenseSettings | undefined\n>(\"PackageLicense\", async (json, { file, root, resolve, config }) => {\n\tconst skipPrivate = config?.skipPrivate ?? true;\n\tconst licenseFileName = config?.licenseFileName ?? DEFAULT_LICENSE_FILE_NAME;\n\n\t// Skip private packages if configured to do so\n\tif (skipPrivate && json.private === true) {\n\t\treturn true;\n\t}\n\n\tconst packageName = json.name ?? \"unknown\";\n\t// file is an absolute path, get the directory containing package.json\n\tconst packageDir = path.dirname(file);\n\tconst packageLicensePath = path.join(packageDir, licenseFileName);\n\tconst rootLicensePath = path.join(root, licenseFileName);\n\n\t// Check if root LICENSE exists\n\tif (!existsSync(rootLicensePath)) {\n\t\treturn {\n\t\t\tname: POLICY_NAME,\n\t\t\tfile,\n\t\t\tautoFixable: false,\n\t\t\terrorMessages: [\n\t\t\t\t`Cannot validate package LICENSE: root ${licenseFileName} file not found`,\n\t\t\t],\n\t\t};\n\t}\n\n\t// Check if package LICENSE exists\n\tif (!existsSync(packageLicensePath)) {\n\t\tif (resolve) {\n\t\t\treturn await copyLicenseFile(\n\t\t\t\trootLicensePath,\n\t\t\t\tpackageLicensePath,\n\t\t\t\tPOLICY_NAME,\n\t\t\t\tfile,\n\t\t\t\tpackageName,\n\t\t\t\tlicenseFileName,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tname: POLICY_NAME,\n\t\t\tfile,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\t`${licenseFileName} file missing for package \"${packageName}\"`,\n\t\t\t],\n\t\t};\n\t}\n\n\t// Compare package LICENSE with root LICENSE\n\tconst [packageLicenseContent, rootLicenseContent] = await Promise.all([\n\t\treadFile(packageLicensePath, \"utf-8\"),\n\t\treadFile(rootLicensePath, \"utf-8\"),\n\t]);\n\n\tif (packageLicenseContent !== rootLicenseContent) {\n\t\tif (resolve) {\n\t\t\treturn await copyLicenseFile(\n\t\t\t\trootLicensePath,\n\t\t\t\tpackageLicensePath,\n\t\t\t\tPOLICY_NAME,\n\t\t\t\tfile,\n\t\t\t\tpackageName,\n\t\t\t\tlicenseFileName,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tname: POLICY_NAME,\n\t\t\tfile,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\t`${licenseFileName} file in package \"${packageName}\" doesn't match root ${licenseFileName}`,\n\t\t\t],\n\t\t};\n\t}\n\n\treturn true;\n});\n"]}
1
+ {"version":3,"file":"PackageLicense.js","sourceRoot":"","sources":["../../src/policies/PackageLicense.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { copyFile, readFile } from \"node:fs/promises\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Policy settings for the PackageLicense repo policy.\n *\n * @alpha\n */\nexport interface PackageLicenseSettings {\n\t/**\n\t * Whether to skip validation for private packages.\n\t *\n\t * @defaultValue true\n\t *\n\t * @remarks\n\t *\n\t * Private packages (those with `private: true` in package.json) are typically\n\t * not published and may not need a LICENSE file. Set to `false` to require\n\t * LICENSE files for all packages.\n\t */\n\tskipPrivate?: boolean;\n\n\t/**\n\t * The name of the LICENSE file to look for and sync.\n\t *\n\t * @defaultValue \"LICENSE\"\n\t */\n\tlicenseFileName?: string;\n}\n\nconst DEFAULT_LICENSE_FILE_NAME = \"LICENSE\";\nconst POLICY_NAME = \"PackageLicense\";\n\n/**\n * Copies the root LICENSE file to the package directory.\n * @returns A PolicyFixResult indicating success or failure.\n */\nasync function copyLicenseFile(\n\trootLicensePath: string,\n\tpackageLicensePath: string,\n\tpolicyName: string,\n\tfile: string,\n\tpackageName: string,\n\tlicenseFileName: string,\n\tisCreate: boolean,\n): Promise<PolicyFixResult> {\n\ttry {\n\t\tawait copyFile(rootLicensePath, packageLicensePath);\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\tresolved: true,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\tisCreate\n\t\t\t\t\t? `Created ${licenseFileName} file for package \"${packageName}\"`\n\t\t\t\t\t: `Updated ${licenseFileName} file for package \"${packageName}\" to match root`,\n\t\t\t],\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\tresolved: false,\n\t\t\tautoFixable: true,\n\t\t\terrorMessages: [\n\t\t\t\tisCreate\n\t\t\t\t\t? `Failed to copy ${licenseFileName} to package \"${packageName}\"`\n\t\t\t\t\t: `Failed to update ${licenseFileName} for package \"${packageName}\"`,\n\t\t\t],\n\t\t};\n\t}\n}\n\n/**\n * A repo policy that ensures each package has a LICENSE file that matches the root LICENSE.\n *\n * @remarks\n *\n * This policy is essential for monorepos where individual packages are published\n * to npm. Each published package should include a LICENSE file, and it should\n * match the root repository's LICENSE to ensure consistent licensing.\n *\n * The policy:\n * 1. Checks if a LICENSE file exists in the package directory\n * 2. Compares it with the root LICENSE file\n * 3. Can auto-fix by copying the root LICENSE to the package directory\n *\n * By default, private packages are skipped since they're not published.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageLicense } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * // Use defaults (skip private, look for LICENSE)\n * makePolicy(PackageLicense),\n *\n * // Or require LICENSE for all packages including private\n * makePolicy(PackageLicense, { skipPrivate: false }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageLicense = definePackagePolicy<\n\tPackageJson,\n\tPackageLicenseSettings | undefined\n>({\n\tname: \"PackageLicense\",\n\tdescription:\n\t\t\"Ensures each package has a LICENSE file that matches the root repository LICENSE.\",\n\thandler: async (json, { file, root, resolve, config }) => {\n\t\tconst skipPrivate = config?.skipPrivate ?? true;\n\t\tconst licenseFileName =\n\t\t\tconfig?.licenseFileName ?? DEFAULT_LICENSE_FILE_NAME;\n\n\t\t// Skip private packages if configured to do so\n\t\tif (skipPrivate && json.private === true) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst packageName = json.name ?? \"unknown\";\n\t\t// file is an absolute path, get the directory containing package.json\n\t\tconst packageDir = path.dirname(file);\n\t\tconst packageLicensePath = path.join(packageDir, licenseFileName);\n\t\tconst rootLicensePath = path.join(root, licenseFileName);\n\n\t\t// Check if root LICENSE exists\n\t\tif (!existsSync(rootLicensePath)) {\n\t\t\treturn {\n\t\t\t\tname: POLICY_NAME,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: false,\n\t\t\t\terrorMessages: [\n\t\t\t\t\t`Cannot validate package LICENSE: root ${licenseFileName} file not found`,\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Check if package LICENSE exists\n\t\tif (!existsSync(packageLicensePath)) {\n\t\t\tif (resolve) {\n\t\t\t\treturn await copyLicenseFile(\n\t\t\t\t\trootLicensePath,\n\t\t\t\t\tpackageLicensePath,\n\t\t\t\t\tPOLICY_NAME,\n\t\t\t\t\tfile,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tlicenseFileName,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tname: POLICY_NAME,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [\n\t\t\t\t\t`${licenseFileName} file missing for package \"${packageName}\"`,\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Compare package LICENSE with root LICENSE\n\t\tconst [packageLicenseContent, rootLicenseContent] = await Promise.all([\n\t\t\treadFile(packageLicensePath, \"utf-8\"),\n\t\t\treadFile(rootLicensePath, \"utf-8\"),\n\t\t]);\n\n\t\tif (packageLicenseContent !== rootLicenseContent) {\n\t\t\tif (resolve) {\n\t\t\t\treturn await copyLicenseFile(\n\t\t\t\t\trootLicensePath,\n\t\t\t\t\tpackageLicensePath,\n\t\t\t\t\tPOLICY_NAME,\n\t\t\t\t\tfile,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tlicenseFileName,\n\t\t\t\t\tfalse,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tname: POLICY_NAME,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [\n\t\t\t\t\t`${licenseFileName} file in package \"${packageName}\" doesn't match root ${licenseFileName}`,\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\treturn true;\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PackagePrivateField.d.ts","sourceRoot":"","sources":["../../src/policies/PackagePrivateField.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACpD;AA+DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,mBAAmB,gFA0E9B,CAAC"}
1
+ {"version":3,"file":"PackagePrivateField.d.ts","sourceRoot":"","sources":["../../src/policies/PackagePrivateField.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACpD;AA+DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,mBAAmB,gFA+E9B,CAAC"}