@ng-prism/core 21.6.1 → 21.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,16 +2,18 @@
2
2
 
3
3
  Lightweight, Angular-native component showcase tool. Annotate components with `@Showcase` — no separate story files needed.
4
4
 
5
- [![Angular](https://img.shields.io/badge/Angular-21+-dd0031)](https://angular.dev)
5
+ [![Angular](https://img.shields.io/badge/Angular-19+-dd0031)](https://angular.dev)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178c6)](https://www.typescriptlang.org)
7
7
  [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
8
8
 
9
+ **[Live Demo](https://dyingangel666.github.io/ng-prism/demo/)** · **[Documentation](https://dyingangel666.github.io/ng-prism/)**
10
+
9
11
  ## Features
10
12
 
11
13
  - **Zero-config discovery** — TypeScript Compiler API scans your library at build time
12
14
  - **Signal-native** — works with `input()` / `output()` signals
13
15
  - **Directive support** — showcase directives with configurable host elements
14
- - **Plugin architecture** — JSDoc, A11y, Figma, Performance, Box Model, Coverage plugins
16
+ - **Plugin architecture** — JSDoc, A11y, Figma, Performance, Box Model, Coverage
15
17
  - **Live Controls** — auto-generated input controls with type-aware editors
16
18
  - **Code Snippets** — live-updating Angular template snippets per variant
17
19
  - **Component Pages** — free-form demo pages for complex components
@@ -82,14 +84,9 @@ export default defineConfig({
82
84
 
83
85
  theme: {
84
86
  '--prism-primary': '#00a67e',
85
- '--prism-bg': '#ffffff',
86
87
  '--prism-font-sans': "'Inter', sans-serif",
87
88
  },
88
89
 
89
- ui: {
90
- header: MyCustomHeaderComponent,
91
- },
92
-
93
90
  appProviders: [
94
91
  provideAnimationsAsync(),
95
92
  provideHttpClient(),
@@ -122,7 +119,6 @@ export class TooltipDirective { ... }
122
119
  For complex components that need template projections or mock data:
123
120
 
124
121
  ```typescript
125
- // Register in main.ts
126
122
  providePrism(PRISM_RUNTIME_MANIFEST, config, {
127
123
  componentPages: [
128
124
  { title: 'Table Demo', category: 'Data', component: TableDemoPage },
@@ -135,11 +131,9 @@ Link to a `@Showcase`-decorated component for combined API docs + custom renderi
135
131
  ```typescript
136
132
  @Showcase({
137
133
  title: 'Table',
138
- renderPage: 'Table Demo', // delegates rendering to the page
134
+ renderPage: 'Table Demo',
139
135
  variants: [{ name: 'Default', inputs: { height: '400px' } }],
140
136
  })
141
- @Component({ selector: 'my-table' })
142
- export class TableComponent { ... }
143
137
  ```
144
138
 
145
139
  ## Official Plugins
@@ -154,18 +148,12 @@ export class TableComponent { ... }
154
148
 
155
149
  > **Note:** Accessibility auditing (axe-core) is built into ng-prism core — no plugin needed.
156
150
 
157
- ## Documentation
158
-
159
- Full documentation with API reference, plugin guide, and advanced configuration:
160
-
161
- **[ng-prism Documentation](https://your-org.github.io/ng-prism/)**
162
-
163
151
  ## Requirements
164
152
 
165
153
  - Angular >= 19
166
154
  - TypeScript >= 5.9
167
- - Components must use `input()` / `output()` signals (not `@Input()` / `@Output()` decorators)
155
+ - Components must use `input()` / `output()` signals
168
156
 
169
157
  ## License
170
158
 
171
- MIT
159
+ [MIT](./LICENSE)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAIV,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAqOtD,wBAAgB,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAOvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAIV,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA6RtD,wBAAgB,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAUvD"}
@@ -173,11 +173,62 @@ function createConfigFile() {
173
173
  return tree;
174
174
  };
175
175
  }
176
+ function addGitignoreEntry(options) {
177
+ return (tree) => {
178
+ const prismProjectName = `${options.project}-prism`;
179
+ const entry = `projects/${prismProjectName}/src/prism-manifest.ts`;
180
+ const gitignorePath = '.gitignore';
181
+ const buffer = tree.read(gitignorePath);
182
+ if (buffer) {
183
+ const content = buffer.toString('utf-8');
184
+ if (content.includes(entry))
185
+ return tree;
186
+ tree.overwrite(gitignorePath, content.trimEnd() + '\n' + entry + '\n');
187
+ }
188
+ else {
189
+ tree.create(gitignorePath, entry + '\n');
190
+ }
191
+ return tree;
192
+ };
193
+ }
194
+ function logSetupSummary(options) {
195
+ return (_tree, context) => {
196
+ const prismProjectName = `${options.project}-prism`;
197
+ context.logger.info('');
198
+ context.logger.info('ng-prism setup complete:');
199
+ context.logger.info(` Prism app project: ${prismProjectName}`);
200
+ context.logger.info(` Config file: ng-prism.config.ts`);
201
+ context.logger.info(` Dev server: ng run ${options.project}:prism`);
202
+ context.logger.info(` Production build: ng run ${options.project}:prism-build`);
203
+ context.logger.info(` Strip decorators: npm run strip-showcase`);
204
+ context.logger.info('');
205
+ };
206
+ }
207
+ function addStripShowcaseScript(options) {
208
+ return (tree) => {
209
+ const pkgPath = 'package.json';
210
+ const buffer = tree.read(pkgPath);
211
+ if (!buffer)
212
+ return tree;
213
+ const pkg = JSON.parse(buffer.toString('utf-8'));
214
+ if (!pkg.scripts)
215
+ pkg.scripts = {};
216
+ const scriptName = 'strip-showcase';
217
+ if (pkg.scripts[scriptName])
218
+ return tree;
219
+ pkg.scripts[scriptName] = `ng-prism-strip dist/${options.project}`;
220
+ tree.overwrite(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
221
+ return tree;
222
+ };
223
+ }
176
224
  export function ngAdd(options) {
177
225
  return chain([
178
226
  addPrismAppProject(options),
179
227
  addBuilderTargets(options),
180
228
  addTsConfigPaths(options),
181
229
  createConfigFile(),
230
+ addStripShowcaseScript(options),
231
+ addGitignoreEntry(options),
232
+ logSetupSummary(options),
182
233
  ]);
183
234
  }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/transformer/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { stripShowcaseFromDirectory } from './strip-directory.js';
3
+ const dir = process.argv[2];
4
+ if (!dir) {
5
+ console.error('Usage: ng-prism-strip <dist-dir>');
6
+ process.exit(1);
7
+ }
8
+ stripShowcaseFromDirectory(dir).then((result) => {
9
+ console.log(`Stripped @Showcase from ${result.strippedFiles} of ${result.totalFiles} files.`);
10
+ }, (error) => {
11
+ console.error(`Error: ${error.message}`);
12
+ process.exit(1);
13
+ });
@@ -0,0 +1,3 @@
1
+ export { createShowcaseStripTransformer, stripShowcaseDecorators, } from './showcase-strip.transformer.js';
2
+ export { stripShowcaseFromDirectory, type StripResult, } from './strip-directory.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transformer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createShowcaseStripTransformer, stripShowcaseDecorators, } from './showcase-strip.transformer.js';
2
+ export { stripShowcaseFromDirectory, } from './strip-directory.js';
@@ -0,0 +1,4 @@
1
+ import ts from 'typescript';
2
+ export declare function createShowcaseStripTransformer(): ts.TransformerFactory<ts.SourceFile>;
3
+ export declare function stripShowcaseDecorators(source: string, fileName?: string): string;
4
+ //# sourceMappingURL=showcase-strip.transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showcase-strip.transformer.d.ts","sourceRoot":"","sources":["../../src/transformer/showcase-strip.transformer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAmK5B,wBAAgB,8BAA8B,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,UAAU,CAAC,CAuCrF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,MAAM,CAWpF"}
@@ -0,0 +1,147 @@
1
+ import ts from 'typescript';
2
+ const SHOWCASE_MODULE_PREFIXES = ['@ng-prism/core', 'ng-prism'];
3
+ function isShowcaseModule(specifier) {
4
+ return SHOWCASE_MODULE_PREFIXES.some((prefix) => specifier === prefix || specifier.startsWith(prefix + '/'));
5
+ }
6
+ function isShowcaseCall(expr, names) {
7
+ return ts.isCallExpression(expr)
8
+ && ts.isIdentifier(expr.expression)
9
+ && names.has(expr.expression.text);
10
+ }
11
+ function isLoweredShowcaseCall(expr, names) {
12
+ if (!ts.isCallExpression(expr))
13
+ return false;
14
+ return isShowcaseCall(expr.expression, names);
15
+ }
16
+ function tryHandleDecorateStatement(stmt, names, factory) {
17
+ const expr = stmt.expression;
18
+ if (!ts.isBinaryExpression(expr) || expr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) {
19
+ return undefined;
20
+ }
21
+ const rhs = expr.right;
22
+ if (!ts.isCallExpression(rhs) || !ts.isIdentifier(rhs.expression) || rhs.expression.text !== '__decorate') {
23
+ return undefined;
24
+ }
25
+ const args = rhs.arguments;
26
+ if (args.length < 2 || !ts.isArrayLiteralExpression(args[0])) {
27
+ return undefined;
28
+ }
29
+ const decoratorArray = args[0];
30
+ const hasShowcase = decoratorArray.elements.some((el) => isShowcaseCall(el, names));
31
+ if (!hasShowcase)
32
+ return undefined;
33
+ const remaining = decoratorArray.elements.filter((el) => !isShowcaseCall(el, names));
34
+ if (remaining.length === 0) {
35
+ return { action: 'remove' };
36
+ }
37
+ const newArray = factory.updateArrayLiteralExpression(decoratorArray, remaining);
38
+ const newCall = factory.updateCallExpression(rhs, rhs.expression, rhs.typeArguments, [newArray, ...args.slice(1)]);
39
+ const newBinary = factory.updateBinaryExpression(expr, expr.left, expr.operatorToken, newCall);
40
+ const newStmt = factory.updateExpressionStatement(stmt, newBinary);
41
+ return { action: 'replace', statement: newStmt };
42
+ }
43
+ function isShowcaseDecorator(d, names) {
44
+ return ts.isCallExpression(d.expression)
45
+ && ts.isIdentifier(d.expression.expression)
46
+ && names.has(d.expression.expression.text);
47
+ }
48
+ function stripNativeDecorators(node, names, factory) {
49
+ const decorators = ts.getDecorators(node);
50
+ if (!decorators)
51
+ return undefined;
52
+ const keptDecorators = decorators.filter((d) => !isShowcaseDecorator(d, names));
53
+ if (keptDecorators.length === decorators.length)
54
+ return undefined;
55
+ const modifiers = ts.getModifiers(node) ?? [];
56
+ return factory.updateClassDeclaration(node, [...keptDecorators, ...modifiers], node.name, node.typeParameters, node.heritageClauses, node.members);
57
+ }
58
+ function findShowcaseImports(sourceFile) {
59
+ const localNames = new Set();
60
+ const declarations = new Set();
61
+ for (const stmt of sourceFile.statements) {
62
+ if (!ts.isImportDeclaration(stmt))
63
+ continue;
64
+ if (!ts.isStringLiteral(stmt.moduleSpecifier))
65
+ continue;
66
+ if (!isShowcaseModule(stmt.moduleSpecifier.text))
67
+ continue;
68
+ const namedBindings = stmt.importClause?.namedBindings;
69
+ if (!namedBindings || !ts.isNamedImports(namedBindings))
70
+ continue;
71
+ for (const spec of namedBindings.elements) {
72
+ const importedName = (spec.propertyName ?? spec.name).text;
73
+ if (importedName === 'Showcase') {
74
+ localNames.add(spec.name.text);
75
+ declarations.add(stmt);
76
+ }
77
+ }
78
+ }
79
+ return { localNames, declarations };
80
+ }
81
+ function cleanupImports(statements, info, factory) {
82
+ return statements.reduce((acc, stmt) => {
83
+ if (!ts.isImportDeclaration(stmt) || !info.declarations.has(stmt)) {
84
+ acc.push(stmt);
85
+ return acc;
86
+ }
87
+ const namedBindings = stmt.importClause?.namedBindings;
88
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) {
89
+ acc.push(stmt);
90
+ return acc;
91
+ }
92
+ const remaining = namedBindings.elements.filter((spec) => {
93
+ const importedName = (spec.propertyName ?? spec.name).text;
94
+ return importedName !== 'Showcase';
95
+ });
96
+ if (remaining.length === 0)
97
+ return acc;
98
+ acc.push(factory.updateImportDeclaration(stmt, stmt.modifiers, factory.updateImportClause(stmt.importClause, stmt.importClause.isTypeOnly, stmt.importClause.name, factory.updateNamedImports(namedBindings, remaining)), stmt.moduleSpecifier, stmt.attributes));
99
+ return acc;
100
+ }, []);
101
+ }
102
+ export function createShowcaseStripTransformer() {
103
+ return (context) => {
104
+ const factory = context.factory;
105
+ return (sourceFile) => {
106
+ const importInfo = findShowcaseImports(sourceFile);
107
+ if (importInfo.localNames.size === 0)
108
+ return sourceFile;
109
+ const names = importInfo.localNames;
110
+ const filtered = [];
111
+ for (const stmt of sourceFile.statements) {
112
+ if (ts.isExpressionStatement(stmt)) {
113
+ if (isLoweredShowcaseCall(stmt.expression, names))
114
+ continue;
115
+ const decorateResult = tryHandleDecorateStatement(stmt, names, factory);
116
+ if (decorateResult) {
117
+ if (decorateResult.action === 'replace' && decorateResult.statement) {
118
+ filtered.push(decorateResult.statement);
119
+ }
120
+ continue;
121
+ }
122
+ }
123
+ if (ts.isClassDeclaration(stmt)) {
124
+ const stripped = stripNativeDecorators(stmt, names, factory);
125
+ if (stripped) {
126
+ filtered.push(stripped);
127
+ continue;
128
+ }
129
+ }
130
+ filtered.push(stmt);
131
+ }
132
+ const cleaned = cleanupImports(filtered, importInfo, factory);
133
+ return factory.updateSourceFile(sourceFile, cleaned);
134
+ };
135
+ };
136
+ }
137
+ export function stripShowcaseDecorators(source, fileName = 'file.ts') {
138
+ const sourceFile = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true);
139
+ const importInfo = findShowcaseImports(sourceFile);
140
+ if (importInfo.localNames.size === 0)
141
+ return source;
142
+ const result = ts.transform(sourceFile, [createShowcaseStripTransformer()]);
143
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
144
+ const output = printer.printFile(result.transformed[0]);
145
+ result.dispose();
146
+ return output;
147
+ }
@@ -0,0 +1,6 @@
1
+ export interface StripResult {
2
+ totalFiles: number;
3
+ strippedFiles: number;
4
+ }
5
+ export declare function stripShowcaseFromDirectory(dir: string): Promise<StripResult>;
6
+ //# sourceMappingURL=strip-directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strip-directory.d.ts","sourceRoot":"","sources":["../../src/transformer/strip-directory.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAID,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBlF"}
@@ -0,0 +1,20 @@
1
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { join, extname } from 'node:path';
3
+ import { stripShowcaseDecorators } from './showcase-strip.transformer.js';
4
+ const JS_EXTENSIONS = new Set(['.js', '.mjs']);
5
+ export async function stripShowcaseFromDirectory(dir) {
6
+ const entries = await readdir(dir, { recursive: true });
7
+ const files = entries
8
+ .filter((entry) => JS_EXTENSIONS.has(extname(entry)))
9
+ .map((entry) => join(dir, entry));
10
+ let strippedFiles = 0;
11
+ for (const file of files) {
12
+ const source = await readFile(file, 'utf-8');
13
+ const result = stripShowcaseDecorators(source, file);
14
+ if (result !== source) {
15
+ await writeFile(file, result, 'utf-8');
16
+ strippedFiles++;
17
+ }
18
+ }
19
+ return { totalFiles: files.length, strippedFiles };
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/core",
3
- "version": "21.6.1",
3
+ "version": "21.7.1",
4
4
  "description": "Lightweight Angular-native component showcase — no story files needed.",
5
5
  "keywords": [
6
6
  "angular",
@@ -30,8 +30,16 @@
30
30
  "types": "./dist/plugin/index.d.ts",
31
31
  "import": "./dist/plugin/index.js",
32
32
  "default": "./dist/plugin/index.js"
33
+ },
34
+ "./transformer": {
35
+ "types": "./dist/transformer/index.d.ts",
36
+ "import": "./dist/transformer/index.js",
37
+ "default": "./dist/transformer/index.js"
33
38
  }
34
39
  },
40
+ "bin": {
41
+ "ng-prism-strip": "./dist/transformer/cli.js"
42
+ },
35
43
  "schematics": "./schematics/collection.json",
36
44
  "builders": "./builders.json",
37
45
  "files": [