Skip to content

feat: add singleQuote option to allow custom style for keys with dashes #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ export = styles;

See also [webpack css-loader's camelCase option](https://github.com/webpack/css-loader#camelcase).

#### Use single quotes to class names in the .d.ts files

With `-sq` or `--singleQuote`, you can configure what quote to use. Useful when tools like prettier format your .d.ts files.

#### named exports (enable tree shaking)

With `-e` or `--namedExports`, types are exported as named exports as opposed to default exports.
Expand Down Expand Up @@ -183,6 +187,7 @@ You can set the following options:
- `option.searchDir`: Directory which includes target `*.css` files(default: `'./'`).
- `option.outDir`: Output directory(default: `option.searchDir`).
- `option.camelCase`: Camelize CSS class tokens.
- `option.singleQuote`: Use single quotes on dashed keys.
- `option.namedExports`: Use named exports as opposed to default exports to enable tree shaking. Requires `import * as style from './file.module.css';` (default: `false`)
- `option.allowArbitraryExtensions`: Output filenames that will be compatible with the "arbitrary file extensions" TypeScript feature
- `option.EOL`: EOL (end of line) for the generated `d.ts` files. Possible values `'\n'` or `'\r\n'`(default: `os.EOL`).
Expand Down
1 change: 0 additions & 1 deletion fixtures/kebabed.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.my-class {
color: red;
}

3 changes: 1 addition & 2 deletions fixtures/testStyle.css.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
declare const styles: {
readonly "myClass": string;
readonly myClass: string;
};
export = styles;

6 changes: 6 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ const yarg = yargs(hideBin(process.argv))
type: 'boolean',
alias: 'camelCase',
},
sq: {
desc: 'Use single quotes for writing the keys when they have a dash',
type: 'boolean',
alias: 'singleQuote',
},
e: {
type: 'boolean',
desc: 'Use named exports as opposed to default exports to enable tree shaking.',
Expand Down Expand Up @@ -87,6 +92,7 @@ async function main(): Promise<void> {
outDir: argv.o,
watch: argv.w,
camelCase: argv.c,
singleQuote: argv.sq,
namedExports: argv.e,
dropExtension: argv.d,
allowArbitraryExtensions: argv.a,
Expand Down
14 changes: 4 additions & 10 deletions src/dts-content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ describe('DtsContent', () => {
content.formatted,
`\
declare const styles: {
readonly "myClass": string;
readonly myClass: string;
};
export = styles;

`,
);
});
Expand All @@ -88,7 +87,6 @@ export = styles;
`\
export const __esModule: true;
export const myClass: string;

`,
);
});
Expand All @@ -100,7 +98,6 @@ export const myClass: string;
`\
export const __esModule: true;
export const myClass: string;

`,
);
});
Expand All @@ -117,10 +114,9 @@ export const myClass: string;
content.formatted,
`\
declare const styles: {
readonly "myClass": string;
readonly myClass: string;
};
export = styles;

`,
);
});
Expand All @@ -131,10 +127,9 @@ export = styles;
content.formatted,
`\
declare const styles: {
readonly "myClass": string;
readonly myClass: string;
};
export = styles;

`,
);
});
Expand All @@ -147,10 +142,9 @@ export = styles;
content.formatted,
`\
declare const styles: {
readonly "MyClass": string;
readonly MyClass: string;
};
export = styles;

`,
);
});
Expand Down
29 changes: 19 additions & 10 deletions src/dts-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface DtsContentOptions {
namedExports: boolean;
allowArbitraryExtensions: boolean;
camelCase: CamelCaseOption;
singleQuote?: boolean;
EOL: string;
}

Expand All @@ -31,6 +32,7 @@ export class DtsContent {
private namedExports: boolean;
private allowArbitraryExtensions: boolean;
private camelCase: CamelCaseOption;
private quote: '"' | "'";
private resultList: string[];
private EOL: string;

Expand All @@ -44,6 +46,7 @@ export class DtsContent {
this.namedExports = options.namedExports;
this.allowArbitraryExtensions = options.allowArbitraryExtensions;
this.camelCase = options.camelCase;
this.quote = options.singleQuote ? "'" : '"';
this.EOL = options.EOL;

// when using named exports, camelCase must be enabled by default
Expand All @@ -65,17 +68,18 @@ export class DtsContent {
if (!this.resultList || !this.resultList.length) return 'export {};';

if (this.namedExports) {
return (
['export const __esModule: true;', ...this.resultList.map(line => 'export ' + line), ''].join(this.EOL) +
this.EOL
);
return ['export const __esModule: true;', ...this.resultList.map(line => 'export ' + line), ''].join(this.EOL);
}

return (
['declare const styles: {', ...this.resultList.map(line => ' ' + line), '};', 'export = styles;', ''].join(
this.EOL,
) + this.EOL
);
const data = [
'declare const styles: {',
...this.resultList.map(line => ' ' + line),
'};',
'export = styles;',
'',
].join(this.EOL);

return data;
}

public get tokens(): string[] {
Expand Down Expand Up @@ -149,10 +153,15 @@ export class DtsContent {

private createResultList(): string[] {
const convertKey = this.getConvertKeyMethod(this.camelCase);
const quote = this.camelCase ? '' : this.quote;

const result = this.rawTokenList
.map(k => convertKey(k))
.map(k => (!this.namedExports ? 'readonly "' + k + '": string;' : 'const ' + k + ': string;'))
.map(k => {
const q = k.includes('-') ? quote : '';

return !this.namedExports ? `readonly ${q}${k}${q}: string;` : 'const ' + k + ': string;';
})
.sort();

return result;
Expand Down
14 changes: 7 additions & 7 deletions src/dts-creator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe(DtsCreator, () => {
it('returns DtsContent instance simple css', async () => {
const content = await new DtsCreator().create('fixtures/testStyle.css');
assert.equal(content.contents.length, 1);
assert.equal(content.contents[0], 'readonly "myClass": string;');
assert.equal(content.contents[0], 'readonly myClass: string;');
});

it('rejects an error with invalid CSS', async () => {
Expand All @@ -20,27 +20,27 @@ describe(DtsCreator, () => {
it('returns DtsContent instance from composing css', async () => {
const content = await new DtsCreator().create('fixtures/composer.css');
assert.equal(content.contents.length, 1);
assert.equal(content.contents[0], 'readonly "root": string;');
assert.equal(content.contents[0], 'readonly root: string;');
});

it('returns DtsContent instance from composing css whose has invalid import/composes', async () => {
const content = await new DtsCreator().create('fixtures/invalidComposer.scss');
assert.equal(content.contents.length, 1);
assert.equal(content.contents[0], 'readonly "myClass": string;');
assert.equal(content.contents[0], 'readonly myClass: string;');
});

it('returns DtsContent instance from the pair of path and contents', async () => {
const content = await new DtsCreator().create('fixtures/somePath', `.myClass { color: red }`);
assert.equal(content.contents.length, 1);
assert.equal(content.contents[0], 'readonly "myClass": string;');
assert.equal(content.contents[0], 'readonly myClass: string;');
});

it('returns DtsContent instance combined css', async () => {
const content = await new DtsCreator().create('fixtures/combined/combined.css');
assert.equal(content.contents.length, 3);
assert.equal(content.contents[0], 'readonly "block": string;');
assert.equal(content.contents[1], 'readonly "box": string;');
assert.equal(content.contents[2], 'readonly "myClass": string;');
assert.equal(content.contents[0], 'readonly block: string;');
assert.equal(content.contents[1], 'readonly box: string;');
assert.equal(content.contents[2], 'readonly myClass: string;');
});
});

Expand Down
4 changes: 4 additions & 0 deletions src/dts-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface DtsCreatorOptions {
searchDir?: string;
outDir?: string;
camelCase?: CamelCaseOption;
singleQuote?: boolean;
namedExports?: boolean;
allowArbitraryExtensions?: boolean;
dropExtension?: boolean;
Expand All @@ -26,6 +27,7 @@ export class DtsCreator {
private loader: FileSystemLoader;
private inputDirectory: string;
private camelCase: CamelCaseOption;
private singleQuote?: boolean;
private namedExports: boolean;
private allowArbitraryExtensions: boolean;
private dropExtension: boolean;
Expand All @@ -38,6 +40,7 @@ export class DtsCreator {
this.outDir = options.outDir || this.searchDir;
this.loader = new FileSystemLoader(this.rootDir, options.loaderPlugins);
this.inputDirectory = path.join(this.rootDir, this.searchDir);
this.singleQuote = options.singleQuote;
this.camelCase = options.camelCase;
this.namedExports = !!options.namedExports;
this.allowArbitraryExtensions = !!options.allowArbitraryExtensions;
Expand Down Expand Up @@ -79,6 +82,7 @@ export class DtsCreator {
namedExports: this.namedExports,
allowArbitraryExtensions: this.allowArbitraryExtensions,
camelCase: this.camelCase,
singleQuote: this.singleQuote,
EOL: this.EOL,
});

Expand Down
2 changes: 2 additions & 0 deletions src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface RunOptions {
outDir?: string;
watch?: boolean;
camelCase?: boolean;
singleQuote?: boolean;
namedExports?: boolean;
allowArbitraryExtensions?: boolean;
dropExtension?: boolean;
Expand All @@ -24,6 +25,7 @@ export async function run(searchDir: string, options: RunOptions = {}): Promise<
searchDir,
outDir: options.outDir,
camelCase: options.camelCase,
singleQuote: options.singleQuote,
namedExports: options.namedExports,
allowArbitraryExtensions: options.allowArbitraryExtensions,
dropExtension: options.dropExtension,
Expand Down