Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@rushstack/eslint-plugin-packlets

Package Overview
Dependencies
Maintainers
3
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rushstack/eslint-plugin-packlets - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

18

CHANGELOG.json

@@ -5,2 +5,20 @@ {

{
"version": "0.1.2",
"tag": "@rushstack/eslint-plugin-packlets_v0.1.2",
"date": "Wed, 28 Oct 2020 01:18:03 GMT",
"comments": {
"patch": [
{
"comment": "Fix an exception that occured if a source file was added to the \"src/packlets\" folder, not belonging to any packlet"
},
{
"comment": "Fix an issue where linting was sometimes not performed on MacOS, because Node.js \"path.relative()\" incorrectly assumes that every POSIX file system is case-sensitive"
},
{
"comment": "Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies"
}
]
}
},
{
"version": "0.1.1",

@@ -7,0 +25,0 @@ "tag": "@rushstack/eslint-plugin-packlets_v0.1.1",

11

CHANGELOG.md
# Change Log - @rushstack/eslint-plugin-packlets
This log was last generated on Tue, 06 Oct 2020 00:24:06 GMT and should not be manually modified.
This log was last generated on Wed, 28 Oct 2020 01:18:03 GMT and should not be manually modified.
## 0.1.2
Wed, 28 Oct 2020 01:18:03 GMT
### Patches
- Fix an exception that occured if a source file was added to the "src/packlets" folder, not belonging to any packlet
- Fix an issue where linting was sometimes not performed on MacOS, because Node.js "path.relative()" incorrectly assumes that every POSIX file system is case-sensitive
- Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies
## 0.1.1

@@ -6,0 +15,0 @@ Tue, 06 Oct 2020 00:24:06 GMT

25

lib/circular-deps.js
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.circularDeps = void 0;
const path = __importStar(require("path"));
const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
const PackletAnalyzer_1 = require("./PackletAnalyzer");
const DependencyAnalyzer_1 = require("./DependencyAnalyzer");
const Path_1 = require("./Path");
const circularDeps = {

@@ -64,3 +45,3 @@ meta: {

if (packletImports) {
const tsconfigFileFolder = path.dirname(tsconfigFilePath);
const tsconfigFileFolder = Path_1.Path.dirname(tsconfigFilePath);
const affectedPackletNames = packletImports.map((x) => x.packletName);

@@ -73,3 +54,3 @@ // If 3 different packlets form a circular dependency, we don't need to report the same warning 3 times.

for (const packletImport of packletImports) {
const filePath = path.relative(tsconfigFileFolder, packletImport.fromFilePath);
const filePath = Path_1.Path.relative(tsconfigFileFolder, packletImport.fromFilePath);
report += `"${packletImport.packletName}" is referenced by ${filePath}\n`;

@@ -76,0 +57,0 @@ }

"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DependencyAnalyzer = void 0;
const path = __importStar(require("path"));
const Path_1 = require("./Path");

@@ -45,3 +25,4 @@ var RefFileKind;

static _walkImports(packletName, startingPackletName, refFileMap, program, packletsFolderPath, visitedPacklets, previousNode) {
const packletEntryPoint = path.join(packletsFolderPath, packletName, 'index');
visitedPacklets.add(packletName);
const packletEntryPoint = Path_1.Path.join(packletsFolderPath, packletName, 'index');
const tsSourceFile = program.getSourceFile(packletEntryPoint + '.ts') || program.getSourceFile(packletEntryPoint + '.tsx');

@@ -60,9 +41,24 @@ if (!tsSourceFile) {

if (Path_1.Path.isUnder(referencingFilePath, packletsFolderPath)) {
const referencingRelativePath = path.relative(packletsFolderPath, referencingFilePath);
const referencingRelativePath = Path_1.Path.relative(packletsFolderPath, referencingFilePath);
const referencingPathParts = referencingRelativePath.split(/[\/\\]+/);
const referencingPackletName = referencingPathParts[0];
// Did we return to where we started from?
if (referencingPackletName === startingPackletName) {
// Ignore the degenerate case where the starting node imports itself,
// since @rushstack/packlets/mechanics will already report that.
if (previousNode) {
// Make a new linked list node to record this step of the traversal
const importListNode = {
previousNode: previousNode,
fromFilePath: referencingFilePath,
packletName: packletName
};
// The traversal has returned to the packlet that we started from;
// this means we have detected a circular dependency
return importListNode;
}
}
// Have we already analyzed this packlet?
if (!visitedPacklets.has(packletName)) {
visitedPacklets.add(packletName);
// Make a new linked list node to record this step of the traversal
if (!visitedPacklets.has(referencingPackletName)) {
// Make a new linked list node to record this step of the traversal
const importListNode = {

@@ -73,7 +69,2 @@ previousNode: previousNode,

};
if (referencingPackletName === startingPackletName) {
// The traversal has returned to the packlet that we started from;
// this means we have detected a circular dependency
return importListNode;
}
const result = DependencyAnalyzer._walkImports(referencingPackletName, startingPackletName, refFileMap, program, packletsFolderPath, visitedPacklets, importListNode);

@@ -80,0 +71,0 @@ if (result) {

@@ -12,9 +12,12 @@ "use strict";

messages: {
// InputFileMessageIds
'file-in-packets-folder': 'The "packlets" folder must not contain regular source files',
'invalid-packlet-name': 'Invalid packlet name "{{packletName}}".' +
' The name must be lowercase alphanumeric words separated by hyphens. Example: "my-packlet"',
'misplaced-packlets-folder': 'The packlets folder must be located at "{{expectedPackletsFolder}}"',
'missing-src-folder': 'Expecting to find a "src" folder at: {{srcFolderPath}}',
'missing-tsconfig': 'In order to use @rushstack/eslint-plugin-packlets, your ESLint config file' +
' must configure the TypeScript parser',
'missing-src-folder': 'Expecting to find a "src" folder at: {{srcFolderPath}}',
'packlet-folder-case': 'The packlets folder must be all lower case: {{packletsFolderPath}}',
'invalid-packlet-name': 'Invalid packlet name "{{packletName}}".' +
' The name must be lowercase alphanumeric words separated by hyphens. Example: "my-packlet"',
'misplaced-packlets-folder': 'The packlets folder must be located at "{{expectedPackletsFolder}}"',
// ImportMessageIds
'bypassed-entry-point': 'The import statement does not use the packlet\'s entry point "{{entryPointModulePath}}"',

@@ -21,0 +24,0 @@ 'circular-entry-point': 'Files under a packlet folder must not import from their own index.ts file',

@@ -1,2 +0,2 @@

export declare type InputFileMessageIds = 'missing-tsconfig' | 'missing-src-folder' | 'packlet-folder-case' | 'invalid-packlet-name' | 'misplaced-packlets-folder';
export declare type InputFileMessageIds = 'file-in-packets-folder' | 'invalid-packlet-name' | 'misplaced-packlets-folder' | 'missing-src-folder' | 'missing-tsconfig' | 'packlet-folder-case';
export declare type ImportMessageIds = 'bypassed-entry-point' | 'circular-entry-point' | 'packlet-importing-project-file';

@@ -3,0 +3,0 @@ export interface IAnalyzerError {

@@ -25,3 +25,2 @@ "use strict";

exports.PackletAnalyzer = void 0;
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));

@@ -44,3 +43,3 @@ const Path_1 = require("./Path");

}
srcFolderPath = path.join(path.dirname(tsconfigFilePath), 'src');
srcFolderPath = Path_1.Path.join(Path_1.Path.dirname(tsconfigFilePath), 'src');
if (!fs.existsSync(srcFolderPath)) {

@@ -56,7 +55,7 @@ this.error = { messageId: 'missing-src-folder', data: { srcFolderPath } };

// Example: packlets/my-packlet/index.ts
const inputFilePathRelativeToSrc = path.relative(srcFolderPath, inputFilePath);
const inputFilePathRelativeToSrc = Path_1.Path.relative(srcFolderPath, inputFilePath);
// Example: [ 'packlets', 'my-packlet', 'index.ts' ]
const pathParts = inputFilePathRelativeToSrc.split(/[\/\\]+/);
let underPackletsFolder = false;
const expectedPackletsFolder = path.join(srcFolderPath, 'packlets');
const expectedPackletsFolder = Path_1.Path.join(srcFolderPath, 'packlets');
for (let i = 0; i < pathParts.length; ++i) {

@@ -67,3 +66,3 @@ const pathPart = pathParts[i];

// Example: /path/to/my-project/src/PACKLETS
const packletsFolderPath = path.join(srcFolderPath, ...pathParts.slice(0, i + 1));
const packletsFolderPath = Path_1.Path.join(srcFolderPath, ...pathParts.slice(0, i + 1));
this.error = { messageId: 'packlet-folder-case', data: { packletsFolderPath } };

@@ -84,16 +83,25 @@ return;

}
if (underPackletsFolder && pathParts.length >= 2) {
// Example: 'my-packlet'
const packletName = pathParts[1];
this.inputFilePackletName = packletName;
// Example: 'index.ts' or 'index.tsx'
const thirdPart = pathParts[2];
// Example: 'index'
const thirdPartWithoutExtension = path.parse(thirdPart).name;
if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') {
if (!PackletAnalyzer._validPackletName.test(packletName)) {
this.error = { messageId: 'invalid-packlet-name', data: { packletName } };
return;
if (underPackletsFolder) {
if (pathParts.length === 2) {
// Example: src/packlets/SomeFile.ts
this.error = { messageId: 'file-in-packets-folder' };
return;
}
if (pathParts.length >= 2) {
// Example: 'my-packlet'
const packletName = pathParts[1];
this.inputFilePackletName = packletName;
if (pathParts.length === 3) {
// Example: 'index.ts' or 'index.tsx'
const thirdPart = pathParts[2];
// Example: 'index'
const thirdPartWithoutExtension = Path_1.Path.parse(thirdPart).name;
if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') {
if (!PackletAnalyzer._validPackletName.test(packletName)) {
this.error = { messageId: 'invalid-packlet-name', data: { packletName } };
return;
}
this.isEntryPoint = true;
}
}
this.isEntryPoint = true;
}

@@ -114,9 +122,9 @@ }

// Example: /path/to/my-project/src/packlets/my-packlet
const inputFileFolder = path.dirname(this.inputFilePath);
const inputFileFolder = Path_1.Path.dirname(this.inputFilePath);
// Example: /path/to/my-project/src/other-packlet/index
const importedPath = path.resolve(inputFileFolder, modulePath);
const importedPath = Path_1.Path.resolve(inputFileFolder, modulePath);
// Is the imported path referring to a file under the src/packlets folder?
if (Path_1.Path.isUnder(importedPath, this.packletsFolderPath)) {
// Example: other-packlet/index
const importedPathRelativeToPackletsFolder = path.relative(this.packletsFolderPath, importedPath);
const importedPathRelativeToPackletsFolder = Path_1.Path.relative(this.packletsFolderPath, importedPath);
// Example: [ 'other-packlet', 'index' ]

@@ -134,3 +142,3 @@ const importedPathParts = importedPathRelativeToPackletsFolder.split(/[\/\\]+/);

// import { X } from "../index.js";
const lastPart = path.parse(importedPathParts[importedPathParts.length - 1]).name;
const lastPart = Path_1.Path.parse(importedPathParts[importedPathParts.length - 1]).name;
let pathToCompare;

@@ -141,3 +149,3 @@ if (lastPart.toUpperCase() === 'INDEX') {

// pathToCompare = /path/to/my-project/src/other-packlet
pathToCompare = path.dirname(importedPath);
pathToCompare = Path_1.Path.dirname(importedPath);
}

@@ -148,3 +156,3 @@ else {

// Example: /path/to/my-project/src/other-packlet
const entryPointPath = path.join(this.packletsFolderPath, importedPackletName);
const entryPointPath = Path_1.Path.join(this.packletsFolderPath, importedPackletName);
if (Path_1.Path.isEqual(pathToCompare, entryPointPath)) {

@@ -160,6 +168,6 @@ return {

// Example: /path/to/my-project/src/other-packlet
const entryPointPath = path.join(this.packletsFolderPath, importedPackletName);
const entryPointPath = Path_1.Path.join(this.packletsFolderPath, importedPackletName);
if (!Path_1.Path.isEqual(importedPath, entryPointPath)) {
// Example: "../packlets/other-packlet"
const entryPointModulePath = Path_1.Path.convertToSlashes(path.relative(inputFileFolder, entryPointPath));
const entryPointModulePath = Path_1.Path.convertToSlashes(Path_1.Path.relative(inputFileFolder, entryPointPath));
return {

@@ -166,0 +174,0 @@ messageId: 'bypassed-entry-point',

@@ -0,2 +1,35 @@

/// <reference types="node" />
import * as path from 'path';
export declare type ParsedPath = path.ParsedPath;
export declare class Path {
/**
* Whether the filesystem is assumed to be case sensitive for Path operations.
*
* @remarks
* Regardless of operating system, a given file system's paths may be case-sensitive or case-insensitive.
* If a volume is mounted under a subfolder, then different parts of a path can even have different
* case-sensitivity. The Node.js "path" API naively assumes that all Windows paths are case-insensitive,
* and that all other OS's are case-sensitive. This is way off, for example a modern MacBook has a
* case-insensitive filesystem by default. There isn't an easy workaround because Node.js does not expose
* the native OS APIs that would give accurate answers.
*
* The TypeScript compiler does somewhat better: it performs an empirical test of its own bundle path to see
* whether it can be read using different case. If so, it normalizes all paths to lowercase (sometimes with
* no API for retrieving the real path). This caused our Path.isUnder() to return incorrect answers because
* it relies on Node.js path.relative().
*
* To solve that problem, Path.ts performs an empirical test similar to what the TypeScript compiler does,
* and then we adjust path.relative() to be case insensitive if appropriate.
*
* @see {@link https://nodejs.org/en/docs/guides/working-with-different-filesystems/}
*/
static usingCaseSensitive: boolean;
private static _detectCaseSensitive;
private static _trimTrailingSlashes;
private static _relativeCaseInsensitive;
static relative(from: string, to: string): string;
static dirname(p: string): string;
static join(...paths: string[]): string;
static resolve(...pathSegments: string[]): string;
static parse(pathString: string): ParsedPath;
private static _relativePathRegex;

@@ -3,0 +36,0 @@ /**

@@ -26,4 +26,81 @@ "use strict";

const path = __importStar(require("path"));
// These helpers are borrowed from @rushstack/node-core-library
const fs = __importStar(require("fs"));
class Path {
static _detectCaseSensitive() {
// Can our own file be accessed using a path with different case? If so, then the filesystem is case-insensitive.
return !fs.existsSync(__filename.toUpperCase());
}
// Removes redundant trailing slashes from a path.
static _trimTrailingSlashes(inputPath) {
// Examples:
// "/a/b///\\" --> "/a/b"
// "/" --> "/"
return inputPath.replace(/(?<=[^\/\\])[\/\\]+$/, '');
}
// An implementation of path.relative() that is case-insensitive.
static _relativeCaseInsensitive(from, to) {
// path.relative() apples path.normalize() and also trims any trailing slashes.
// Since we'll be matching toNormalized against result, we need to do that for our string as well.
const normalizedTo = Path._trimTrailingSlashes(path.normalize(to));
// We start by converting everything to uppercase and call path.relative()
const uppercasedFrom = from.toUpperCase();
const uppercasedTo = normalizedTo.toUpperCase();
// The result will be all uppercase because its inputs were uppercased
const uppercasedResult = path.relative(uppercasedFrom, uppercasedTo);
// Are there any cased characters in the result?
if (uppercasedResult.toLowerCase() === uppercasedResult) {
// No cased characters
// Example: "../.."
return uppercasedResult;
}
// Example:
// from="/a/b/c"
// to="/a/b/d/e"
//
// fromNormalized="/A/B/C"
// toNormalized="/A/B/D/E"
//
// result="../D/E"
//
// Scan backwards comparing uppercasedResult versus uppercasedTo, stopping at the first place where they differ.
let resultIndex = uppercasedResult.length;
let toIndex = normalizedTo.length;
for (;;) {
if (resultIndex === 0 || toIndex === 0) {
// Stop if we reach the start of the string
break;
}
if (uppercasedResult.charCodeAt(resultIndex - 1) !== uppercasedTo.charCodeAt(toIndex - 1)) {
// Stop before we reach a character that is different
break;
}
--resultIndex;
--toIndex;
}
// Replace the matching part with the properly cased substring from the "normalizedTo" input
//
// Example:
// ".." + "/d/e" = "../d/e"
return uppercasedResult.substring(0, resultIndex) + normalizedTo.substring(toIndex);
}
static relative(from, to) {
if (!Path.usingCaseSensitive) {
return Path._relativeCaseInsensitive(from, to);
}
return path.relative(from, to);
}
// --------------------------------------------------------------------------------------------------------
// The operations below don't care about case sensitivity
static dirname(p) {
return path.dirname(p);
}
static join(...paths) {
return path.join(...paths);
}
static resolve(...pathSegments) {
return path.resolve(...pathSegments);
}
static parse(pathString) {
return path.parse(pathString);
}
/**

@@ -40,3 +117,3 @@ * Returns true if "childPath" is located inside the "parentFolderPath" folder

static isUnder(childPath, parentFolderPath) {
const relativePath = path.relative(childPath, parentFolderPath);
const relativePath = Path.relative(childPath, parentFolderPath);
return Path._relativePathRegex.test(relativePath);

@@ -52,3 +129,3 @@ }

static isEqual(path1, path2) {
return path.relative(path1, path2) === '';
return Path.relative(path1, path2) === '';
}

@@ -66,3 +143,27 @@ /**

exports.Path = Path;
/**
* Whether the filesystem is assumed to be case sensitive for Path operations.
*
* @remarks
* Regardless of operating system, a given file system's paths may be case-sensitive or case-insensitive.
* If a volume is mounted under a subfolder, then different parts of a path can even have different
* case-sensitivity. The Node.js "path" API naively assumes that all Windows paths are case-insensitive,
* and that all other OS's are case-sensitive. This is way off, for example a modern MacBook has a
* case-insensitive filesystem by default. There isn't an easy workaround because Node.js does not expose
* the native OS APIs that would give accurate answers.
*
* The TypeScript compiler does somewhat better: it performs an empirical test of its own bundle path to see
* whether it can be read using different case. If so, it normalizes all paths to lowercase (sometimes with
* no API for retrieving the real path). This caused our Path.isUnder() to return incorrect answers because
* it relies on Node.js path.relative().
*
* To solve that problem, Path.ts performs an empirical test similar to what the TypeScript compiler does,
* and then we adjust path.relative() to be case insensitive if appropriate.
*
* @see {@link https://nodejs.org/en/docs/guides/working-with-different-filesystems/}
*/
Path.usingCaseSensitive = Path._detectCaseSensitive();
// --------------------------------------------------------------------------------------------------------
// The operations below are borrowed from @rushstack/node-core-library
Path._relativePathRegex = /^[.\/\\]+$/;
//# sourceMappingURL=Path.js.map
{
"name": "@rushstack/eslint-plugin-packlets",
"version": "0.1.1",
"version": "0.1.2",
"description": "A lightweight alternative to NPM packages for organizing source files within a single project",

@@ -5,0 +5,0 @@ "license": "MIT",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc